WordPress.org

Make WordPress Core

Ticket #7474: php-mailer-patch.diff

File php-mailer-patch.diff, 198.7 KB (added by mattyrob, 10 years ago)
  • wp-includes/class-pop3.php

     
    11<?php
     2/*~ class.pop3.php
     3.---------------------------------------------------------------------------.
     4|  Software: PHPMailer - PHP email class                                    |
     5|   Version: 2.0.2                                                          |
     6|   Contact: via sourceforge.net support pages (also www.codeworxtech.com)  |
     7|      Info: http://phpmailer.sourceforge.net                               |
     8|   Support: http://sourceforge.net/projects/phpmailer/                     |
     9| ------------------------------------------------------------------------- |
     10|    Author: Andy Prevost (project admininistrator)                         |
     11|    Author: Brent R. Matzelle (original founder)                           |
     12| Copyright (c) 2004-2007, Andy Prevost. All Rights Reserved.               |
     13| Copyright (c) 2001-2003, Brent R. Matzelle                                |
     14| ------------------------------------------------------------------------- |
     15|   License: Distributed under the Lesser General Public License (LGPL)     |
     16|            http://www.gnu.org/copyleft/lesser.html                        |
     17| This program is distributed in the hope that it will be useful - WITHOUT  |
     18| ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or     |
     19| FITNESS FOR A PARTICULAR PURPOSE.                                         |
     20| ------------------------------------------------------------------------- |
     21| We offer a number of paid services (www.codeworxtech.com):                |
     22| - Web Hosting on highly optimized fast and secure servers                 |
     23| - Technology Consulting                                                   |
     24| - Oursourcing (highly qualified programmers and graphic designers)        |
     25'---------------------------------------------------------------------------'
     26
    227/**
    3  * mail_fetch/setup.php
     28 * POP Before SMTP Authentication Class
    429 *
    5  * @package SquirrelMail
     30 * Author: Richard Davey (rich@corephp.co.uk)
     31 * License: LGPL, see PHPMailer License
    632 *
    7  * @copyright (c) 1999-2006 The SquirrelMail Project Team
     33 * Specifically for PHPMailer to allow POP before SMTP authentication.
     34 * Does not yet work with APOP - if you have an APOP account, contact me
     35 * and we can test changes to this script.
    836 *
    9  * @copyright (c) 1999 CDI (cdi@thewebmasters.net) All Rights Reserved
    10  * Modified by Philippe Mingo 2001 mingo@rotedic.com
    11  * An RFC 1939 compliant wrapper class for the POP3 protocol.
     37 * This class is based on the structure of the SMTP class by Chris Ryan
    1238 *
    13  * Licensed under the GNU GPL. For full terms see the file COPYING.
     39 * This class is rfc 1939 compliant and implements all the commands
     40 * required for POP3 connection, authentication and disconnection.
    1441 *
    15  * pop3 class
    16  *
    17  * $Id$
     42 * @package PHPMailer
     43 * @author Richard Davey
    1844 */
    1945
    20 /**
    21  * POP3
    22  *
    23  * @package SquirrelMail
    24  */
    25 class POP3 {
    26     var $ERROR      = '';       //  Error string.
     46class POP3
     47{
     48  /**
     49   * Default POP3 port
     50   * @var int
     51   */
     52  var $POP3_PORT = 110;
    2753
    28     var $TIMEOUT    = 60;       //  Default timeout before giving up on a
    29                                 //  network operation.
     54  /**
     55   * Default Timeout
     56   * @var int
     57   */
     58  var $POP3_TIMEOUT = 30;
    3059
    31     var $COUNT      = -1;       //  Mailbox msg count
     60  /**
     61   * POP3 Carriage Return + Line Feed
     62   * @var string
     63   */
     64  var $CRLF = "\r\n";
    3265
    33     var $BUFFER     = 512;      //  Socket buffer for socket fgets() calls.
    34                                 //  Per RFC 1939 the returned line a POP3
    35                                 //  server can send is 512 bytes.
     66  /**
     67   * Displaying Debug warnings? (0 = now, 1+ = yes)
     68   * @var int
     69   */
     70  var $do_debug = 2;
    3671
    37     var $FP         = '';       //  The connection to the server's
    38                                 //  file descriptor
     72  /**
     73   * POP3 Mail Server
     74   * @var string
     75   */
     76  var $host;
    3977
    40     var $MAILSERVER = '';       // Set this to hard code the server name
     78  /**
     79   * POP3 Port
     80   * @var int
     81   */
     82  var $port;
    4183
    42     var $DEBUG      = FALSE;    // set to true to echo pop3
    43                                 // commands and responses to error_log
    44                                 // this WILL log passwords!
     84  /**
     85   * POP3 Timeout Value
     86   * @var int
     87   */
     88  var $tval;
    4589
    46     var $BANNER     = '';       //  Holds the banner returned by the
    47                                 //  pop server - used for apop()
     90  /**
     91   * POP3 Username
     92   * @var string
     93   */
     94  var $username;
    4895
    49     var $ALLOWAPOP  = FALSE;    //  Allow or disallow apop()
    50                                 //  This must be set to true
    51                                 //  manually
     96  /**
     97   * POP3 Password
     98   * @var string
     99   */
     100  var $password;
    52101
    53     function POP3 ( $server = '', $timeout = '' ) {
    54         settype($this->BUFFER,"integer");
    55         if( !empty($server) ) {
    56             // Do not allow programs to alter MAILSERVER
    57             // if it is already specified. They can get around
    58             // this if they -really- want to, so don't count on it.
    59             if(empty($this->MAILSERVER))
    60                 $this->MAILSERVER = $server;
    61         }
    62         if(!empty($timeout)) {
    63             settype($timeout,"integer");
    64             $this->TIMEOUT = $timeout;
    65             if (!ini_get('safe_mode'))
    66                 set_time_limit($timeout);
    67         }
    68         return true;
     102  /**#@+
     103   * @access private
     104   */
     105  var $pop_conn;
     106  var $connected;
     107  var $error;     //  Error log array
     108  /**#@-*/
     109
     110  /**
     111   * Constructor, sets the initial values
     112   *
     113   * @return POP3
     114   */
     115  function POP3 ()
     116    {
     117      $this->pop_conn = 0;
     118      $this->connected = false;
     119      $this->error = null;
    69120    }
    70121
    71     function update_timer () {
    72         if (!ini_get('safe_mode'))
    73             set_time_limit($this->TIMEOUT);
    74         return true;
     122  /**
     123   * Combination of public events - connect, login, disconnect
     124   *
     125   * @param string $host
     126   * @param integer $port
     127   * @param integer $tval
     128   * @param string $username
     129   * @param string $password
     130   */
     131  function Authorise ($host, $port = false, $tval = false, $username, $password, $debug_level = 0)
     132  {
     133    $this->host = $host;
     134
     135    //  If no port value is passed, retrieve it
     136    if ($port == false)
     137    {
     138      $this->port = $this->POP3_PORT;
    75139    }
     140    else
     141    {
     142      $this->port = $port;
     143    }
    76144
    77     function connect ($server, $port = 110)  {
    78         //  Opens a socket to the specified server. Unless overridden,
    79         //  port defaults to 110. Returns true on success, false on fail
     145    //  If no port value is passed, retrieve it
     146    if ($tval == false)
     147    {
     148      $this->tval = $this->POP3_TIMEOUT;
     149    }
     150    else
     151    {
     152      $this->tval = $tval;
     153    }
    80154
    81         // If MAILSERVER is set, override $server with it's value
     155    $this->do_debug = $debug_level;
     156    $this->username = $username;
     157    $this->password = $password;
    82158
    83         if (!isset($port) || !$port) {$port = 110;}
    84         if(!empty($this->MAILSERVER))
    85             $server = $this->MAILSERVER;
     159    //  Refresh the error log
     160      $this->error = null;
    86161
    87         if(empty($server)){
    88             $this->ERROR = "POP3 connect: " . _("No server specified");
    89             unset($this->FP);
    90             return false;
    91         }
     162      //  Connect
     163    $result = $this->Connect($this->host, $this->port, $this->tval);
    92164
    93         $fp = @fsockopen("$server", $port, $errno, $errstr);
     165    if ($result)
     166    {
     167      $login_result = $this->Login($this->username, $this->password);
    94168
    95         if(!$fp) {
    96             $this->ERROR = "POP3 connect: " . _("Error ") . "[$errno] [$errstr]";
    97             unset($this->FP);
    98             return false;
    99         }
     169      if ($login_result)
     170      {
     171        $this->Disconnect();
    100172
    101         socket_set_blocking($fp,-1);
    102         $this->update_timer();
    103         $reply = fgets($fp,$this->BUFFER);
    104         $reply = $this->strip_clf($reply);
    105         if($this->DEBUG)
    106             error_log("POP3 SEND [connect: $server] GOT [$reply]",0);
    107         if(!$this->is_ok($reply)) {
    108             $this->ERROR = "POP3 connect: " . _("Error ") . "[$reply]";
    109             unset($this->FP);
    110             return false;
    111         }
    112         $this->FP = $fp;
    113         $this->BANNER = $this->parse_banner($reply);
    114173        return true;
    115     }
     174      }
    116175
    117     function user ($user = "") {
    118         // Sends the USER command, returns true or false
    119 
    120         if( empty($user) ) {
    121             $this->ERROR = "POP3 user: " . _("no login ID submitted");
    122             return false;
    123         } elseif(!isset($this->FP)) {
    124             $this->ERROR = "POP3 user: " . _("connection not established");
    125             return false;
    126         } else {
    127             $reply = $this->send_cmd("USER $user");
    128             if(!$this->is_ok($reply)) {
    129                 $this->ERROR = "POP3 user: " . _("Error ") . "[$reply]";
    130                 return false;
    131             } else
    132                 return true;
    133         }
    134176    }
    135177
    136     function pass ($pass = "")     {
    137         // Sends the PASS command, returns # of msgs in mailbox,
    138         // returns false (undef) on Auth failure
     178    //  We need to disconnect regardless if the login succeeded
     179    $this->Disconnect();
    139180
    140         if(empty($pass)) {
    141             $this->ERROR = "POP3 pass: " . _("No password submitted");
    142             return false;
    143         } elseif(!isset($this->FP)) {
    144             $this->ERROR = "POP3 pass: " . _("connection not established");
    145             return false;
    146         } else {
    147             $reply = $this->send_cmd("PASS $pass");
    148             if(!$this->is_ok($reply)) {
    149                 $this->ERROR = "POP3 pass: " . _("Authentication failed") . " [$reply]";
    150                 $this->quit();
    151                 return false;
    152             } else {
    153                 //  Auth successful.
    154                 $count = $this->last("count");
    155                 $this->COUNT = $count;
    156                 return $count;
    157             }
    158         }
    159     }
     181    return false;
     182  }
    160183
    161     function apop ($login,$pass) {
    162         //  Attempts an APOP login. If this fails, it'll
    163         //  try a standard login. YOUR SERVER MUST SUPPORT
    164         //  THE USE OF THE APOP COMMAND!
    165         //  (apop is optional per rfc1939)
    166 
    167         if(!isset($this->FP)) {
    168             $this->ERROR = "POP3 apop: " . _("No connection to server");
    169             return false;
    170         } elseif(!$this->ALLOWAPOP) {
    171             $retVal = $this->login($login,$pass);
    172             return $retVal;
    173         } elseif(empty($login)) {
    174             $this->ERROR = "POP3 apop: " . _("No login ID submitted");
    175             return false;
    176         } elseif(empty($pass)) {
    177             $this->ERROR = "POP3 apop: " . _("No password submitted");
    178             return false;
    179         } else {
    180             $banner = $this->BANNER;
    181             if( (!$banner) or (empty($banner)) ) {
    182                 $this->ERROR = "POP3 apop: " . _("No server banner") . ' - ' . _("abort");
    183                 $retVal = $this->login($login,$pass);
    184                 return $retVal;
    185             } else {
    186                 $AuthString = $banner;
    187                 $AuthString .= $pass;
    188                 $APOPString = md5($AuthString);
    189                 $cmd = "APOP $login $APOPString";
    190                 $reply = $this->send_cmd($cmd);
    191                 if(!$this->is_ok($reply)) {
    192                     $this->ERROR = "POP3 apop: " . _("apop authentication failed") . ' - ' . _("abort");
    193                     $retVal = $this->login($login,$pass);
    194                     return $retVal;
    195                 } else {
    196                     //  Auth successful.
    197                     $count = $this->last("count");
    198                     $this->COUNT = $count;
    199                     return $count;
    200                 }
    201             }
    202         }
     184  /**
     185   * Connect to the POP3 server
     186   *
     187   * @param string $host
     188   * @param integer $port
     189   * @param integer $tval
     190   * @return boolean
     191   */
     192  function Connect ($host, $port = false, $tval = 30)
     193    {
     194    //  Are we already connected?
     195    if ($this->connected)
     196    {
     197      return true;
    203198    }
    204199
    205     function login ($login = "", $pass = "") {
    206         // Sends both user and pass. Returns # of msgs in mailbox or
    207         // false on failure (or -1, if the error occurs while getting
    208         // the number of messages.)
     200    /*
     201      On Windows this will raise a PHP Warning error if the hostname doesn't exist.
     202      Rather than supress it with @fsockopen, let's capture it cleanly instead
     203    */
    209204
    210         if( !isset($this->FP) ) {
    211             $this->ERROR = "POP3 login: " . _("No connection to server");
    212             return false;
    213         } else {
    214             $fp = $this->FP;
    215             if( !$this->user( $login ) ) {
    216                 //  Preserve the error generated by user()
    217                 return false;
    218             } else {
    219                 $count = $this->pass($pass);
    220                 if( (!$count) || ($count == -1) ) {
    221                     //  Preserve the error generated by last() and pass()
    222                     return false;
    223                 } else
    224                     return $count;
    225             }
    226         }
    227     }
     205    set_error_handler(array(&$this, 'catchWarning'));
    228206
    229     function top ($msgNum, $numLines = "0") {
    230         //  Gets the header and first $numLines of the msg body
    231         //  returns data in an array with each returned line being
    232         //  an array element. If $numLines is empty, returns
    233         //  only the header information, and none of the body.
     207    //  Connect to the POP3 server
     208    $this->pop_conn = fsockopen($host,    //  POP3 Host
     209                  $port,    //  Port #
     210                  $errno,   //  Error Number
     211                  $errstr,  //  Error Message
     212                  $tval);   //  Timeout (seconds)
    234213
    235         if(!isset($this->FP)) {
    236             $this->ERROR = "POP3 top: " . _("No connection to server");
    237             return false;
    238         }
    239         $this->update_timer();
     214    //  Restore the error handler
     215    restore_error_handler();
    240216
    241         $fp = $this->FP;
    242         $buffer = $this->BUFFER;
    243         $cmd = "TOP $msgNum $numLines";
    244         fwrite($fp, "TOP $msgNum $numLines\r\n");
    245         $reply = fgets($fp, $buffer);
    246         $reply = $this->strip_clf($reply);
    247         if($this->DEBUG) {
    248             @error_log("POP3 SEND [$cmd] GOT [$reply]",0);
    249         }
    250         if(!$this->is_ok($reply))
    251         {
    252             $this->ERROR = "POP3 top: " . _("Error ") . "[$reply]";
    253             return false;
    254         }
    255 
    256         $count = 0;
    257         $MsgArray = array();
    258 
    259         $line = fgets($fp,$buffer);
    260         while ( !ereg("^\.\r\n",$line))
    261         {
    262             $MsgArray[$count] = $line;
    263             $count++;
    264             $line = fgets($fp,$buffer);
    265             if(empty($line))    { break; }
    266         }
    267 
    268         return $MsgArray;
     217    //  Does the Error Log now contain anything?
     218    if ($this->error && $this->do_debug >= 1)
     219    {
     220        $this->displayErrors();
    269221    }
    270222
    271     function pop_list ($msgNum = "") {
    272         //  If called with an argument, returns that msgs' size in octets
    273         //  No argument returns an associative array of undeleted
    274         //  msg numbers and their sizes in octets
     223    //  Did we connect?
     224      if ($this->pop_conn == false)
     225      {
     226        //  It would appear not...
     227        $this->error = array(
     228          'error' => "Failed to connect to server $host on port $port",
     229          'errno' => $errno,
     230          'errstr' => $errstr
     231        );
    275232
    276         if(!isset($this->FP))
     233        if ($this->do_debug >= 1)
    277234        {
    278             $this->ERROR = "POP3 pop_list: " . _("No connection to server");
    279             return false;
     235          $this->displayErrors();
    280236        }
    281         $fp = $this->FP;
    282         $Total = $this->COUNT;
    283         if( (!$Total) or ($Total == -1) )
    284         {
    285             return false;
    286         }
    287         if($Total == 0)
    288         {
    289             return array("0","0");
    290             // return -1;   // mailbox empty
    291         }
    292237
    293         $this->update_timer();
     238        return false;
     239      }
    294240
    295         if(!empty($msgNum))
    296         {
    297             $cmd = "LIST $msgNum";
    298             fwrite($fp,"$cmd\r\n");
    299             $reply = fgets($fp,$this->BUFFER);
    300             $reply = $this->strip_clf($reply);
    301             if($this->DEBUG) {
    302                 @error_log("POP3 SEND [$cmd] GOT [$reply]",0);
    303             }
    304             if(!$this->is_ok($reply))
    305             {
    306                 $this->ERROR = "POP3 pop_list: " . _("Error ") . "[$reply]";
    307                 return false;
    308             }
    309             list($junk,$num,$size) = preg_split('/\s+/',$reply);
    310             return $size;
    311         }
    312         $cmd = "LIST";
    313         $reply = $this->send_cmd($cmd);
    314         if(!$this->is_ok($reply))
    315         {
    316             $reply = $this->strip_clf($reply);
    317             $this->ERROR = "POP3 pop_list: " . _("Error ") .  "[$reply]";
    318             return false;
    319         }
    320         $MsgArray = array();
    321         $MsgArray[0] = $Total;
    322         for($msgC=1;$msgC <= $Total; $msgC++)
    323         {
    324             if($msgC > $Total) { break; }
    325             $line = fgets($fp,$this->BUFFER);
    326             $line = $this->strip_clf($line);
    327             if(ereg("^\.",$line))
    328             {
    329                 $this->ERROR = "POP3 pop_list: " . _("Premature end of list");
    330                 return false;
    331             }
    332             list($thisMsg,$msgSize) = preg_split('/\s+/',$line);
    333             settype($thisMsg,"integer");
    334             if($thisMsg != $msgC)
    335             {
    336                 $MsgArray[$msgC] = "deleted";
    337             }
    338             else
    339             {
    340                 $MsgArray[$msgC] = $msgSize;
    341             }
    342         }
    343         return $MsgArray;
    344     }
     241      //  Increase the stream time-out
    345242
    346     function get ($msgNum) {
    347         //  Retrieve the specified msg number. Returns an array
    348         //  where each line of the msg is an array element.
    349 
    350         if(!isset($this->FP))
     243      //  Check for PHP 4.3.0 or later
     244      if (version_compare(phpversion(), '4.3.0', 'ge'))
     245      {
     246        stream_set_timeout($this->pop_conn, $tval, 0);
     247      }
     248      else
     249      {
     250        //  Does not work on Windows
     251        if (substr(PHP_OS, 0, 3) !== 'WIN')
    351252        {
    352             $this->ERROR = "POP3 get: " . _("No connection to server");
    353             return false;
     253          socket_set_timeout($this->pop_conn, $tval, 0);
    354254        }
     255      }
    355256
    356         $this->update_timer();
     257    //  Get the POP3 server response
     258      $pop3_response = $this->getResponse();
    357259
    358         $fp = $this->FP;
    359         $buffer = $this->BUFFER;
    360         $cmd = "RETR $msgNum";
    361         $reply = $this->send_cmd($cmd);
     260      //  Check for the +OK
     261      if ($this->checkResponse($pop3_response))
     262      {
     263      //  The connection is established and the POP3 server is talking
     264      $this->connected = true;
     265        return true;
     266      }
    362267
    363         if(!$this->is_ok($reply))
    364         {
    365             $this->ERROR = "POP3 get: " . _("Error ") . "[$reply]";
    366             return false;
    367         }
     268    }
    368269
    369         $count = 0;
    370         $MsgArray = array();
     270    /**
     271     * Login to the POP3 server (does not support APOP yet)
     272     *
     273     * @param string $username
     274     * @param string $password
     275     * @return boolean
     276     */
     277    function Login ($username = '', $password = '')
     278    {
     279      if ($this->connected == false)
     280      {
     281        $this->error = 'Not connected to POP3 server';
    371282
    372         $line = fgets($fp,$buffer);
    373         while ( !ereg("^\.\r\n",$line))
     283        if ($this->do_debug >= 1)
    374284        {
    375             if ( $line{0} == '.' ) { $line = substr($line,1); }
    376             $MsgArray[$count] = $line;
    377             $count++;
    378             $line = fgets($fp,$buffer);
    379             if(empty($line))    { break; }
     285          $this->displayErrors();
    380286        }
    381         return $MsgArray;
    382     }
     287      }
    383288
    384     function last ( $type = "count" ) {
    385         //  Returns the highest msg number in the mailbox.
    386         //  returns -1 on error, 0+ on success, if type != count
    387         //  results in a popstat() call (2 element array returned)
     289      if (empty($username))
     290      {
     291        $username = $this->username;
     292      }
    388293
    389         $last = -1;
    390         if(!isset($this->FP))
    391         {
    392             $this->ERROR = "POP3 last: " . _("No connection to server");
    393             return $last;
    394         }
     294      if (empty($password))
     295      {
     296        $password = $this->password;
     297      }
    395298
    396         $reply = $this->send_cmd("STAT");
    397         if(!$this->is_ok($reply))
    398         {
    399             $this->ERROR = "POP3 last: " . _("Error ") . "[$reply]";
    400             return $last;
    401         }
     299    $pop_username = "USER $username" . $this->CRLF;
     300    $pop_password = "PASS $password" . $this->CRLF;
    402301
    403         $Vars = preg_split('/\s+/',$reply);
    404         $count = $Vars[1];
    405         $size = $Vars[2];
    406         settype($count,"integer");
    407         settype($size,"integer");
    408         if($type != "count")
    409         {
    410             return array($count,$size);
    411         }
    412         return $count;
    413     }
     302      //  Send the Username
     303      $this->sendString($pop_username);
     304      $pop3_response = $this->getResponse();
    414305
    415     function reset () {
    416         //  Resets the status of the remote server. This includes
    417         //  resetting the status of ALL msgs to not be deleted.
    418         //  This method automatically closes the connection to the server.
     306      if ($this->checkResponse($pop3_response))
     307      {
     308        //  Send the Password
     309        $this->sendString($pop_password);
     310        $pop3_response = $this->getResponse();
    419311
    420         if(!isset($this->FP))
     312        if ($this->checkResponse($pop3_response))
    421313        {
    422             $this->ERROR = "POP3 reset: " . _("No connection to server");
    423             return false;
     314          return true;
    424315        }
    425         $reply = $this->send_cmd("RSET");
    426         if(!$this->is_ok($reply))
     316        else
    427317        {
    428             //  The POP3 RSET command -never- gives a -ERR
    429             //  response - if it ever does, something truely
    430             //  wild is going on.
    431 
    432             $this->ERROR = "POP3 reset: " . _("Error ") . "[$reply]";
    433             @error_log("POP3 reset: ERROR [$reply]",0);
     318          return false;
    434319        }
    435         $this->quit();
    436         return true;
     320      }
     321      else
     322      {
     323        return false;
     324      }
    437325    }
    438326
    439     function send_cmd ( $cmd = "" )
     327    /**
     328     * Disconnect from the POP3 server
     329     */
     330    function Disconnect ()
    440331    {
    441         //  Sends a user defined command string to the
    442         //  POP server and returns the results. Useful for
    443         //  non-compliant or custom POP servers.
    444         //  Do NOT includ the \r\n as part of your command
    445         //  string - it will be appended automatically.
     332      $this->sendString('QUIT');
    446333
    447         //  The return value is a standard fgets() call, which
    448         //  will read up to $this->BUFFER bytes of data, until it
    449         //  encounters a new line, or EOF, whichever happens first.
    450 
    451         //  This method works best if $cmd responds with only
    452         //  one line of data.
    453 
    454         if(!isset($this->FP))
    455         {
    456             $this->ERROR = "POP3 send_cmd: " . _("No connection to server");
    457             return false;
    458         }
    459 
    460         if(empty($cmd))
    461         {
    462             $this->ERROR = "POP3 send_cmd: " . _("Empty command string");
    463             return "";
    464         }
    465 
    466         $fp = $this->FP;
    467         $buffer = $this->BUFFER;
    468         $this->update_timer();
    469         fwrite($fp,"$cmd\r\n");
    470         $reply = fgets($fp,$buffer);
    471         $reply = $this->strip_clf($reply);
    472         if($this->DEBUG) { @error_log("POP3 SEND [$cmd] GOT [$reply]",0); }
    473         return $reply;
     334      fclose($this->pop_conn);
    474335    }
    475336
    476     function quit() {
    477         //  Closes the connection to the POP3 server, deleting
    478         //  any msgs marked as deleted.
     337    /*
     338      ---------------
     339      Private Methods
     340      ---------------
     341    */
    479342
    480         if(!isset($this->FP))
    481         {
    482             $this->ERROR = "POP3 quit: " . _("connection does not exist");
    483             return false;
    484         }
    485         $fp = $this->FP;
    486         $cmd = "QUIT";
    487         fwrite($fp,"$cmd\r\n");
    488         $reply = fgets($fp,$this->BUFFER);
    489         $reply = $this->strip_clf($reply);
    490         if($this->DEBUG) { @error_log("POP3 SEND [$cmd] GOT [$reply]",0); }
    491         fclose($fp);
    492         unset($this->FP);
    493         return true;
    494     }
     343    /**
     344     * Get the socket response back.
     345     * $size is the maximum number of bytes to retrieve
     346     *
     347     * @param integer $size
     348     * @return string
     349     */
     350    function getResponse ($size = 128)
     351    {
     352      $pop3_response = fgets($this->pop_conn, $size);
    495353
    496     function popstat () {
    497         //  Returns an array of 2 elements. The number of undeleted
    498         //  msgs in the mailbox, and the size of the mbox in octets.
    499 
    500         $PopArray = $this->last("array");
    501 
    502         if($PopArray == -1) { return false; }
    503 
    504         if( (!$PopArray) or (empty($PopArray)) )
    505         {
    506             return false;
    507         }
    508         return $PopArray;
     354      return $pop3_response;
    509355    }
    510356
    511     function uidl ($msgNum = "")
     357    /**
     358     * Send a string down the open socket connection to the POP3 server
     359     *
     360     * @param string $string
     361     * @return integer
     362     */
     363    function sendString ($string)
    512364    {
    513         //  Returns the UIDL of the msg specified. If called with
    514         //  no arguments, returns an associative array where each
    515         //  undeleted msg num is a key, and the msg's uidl is the element
    516         //  Array element 0 will contain the total number of msgs
     365      $bytes_sent = fwrite($this->pop_conn, $string, strlen($string));
    517366
    518         if(!isset($this->FP)) {
    519             $this->ERROR = "POP3 uidl: " . _("No connection to server");
    520             return false;
    521         }
     367      return $bytes_sent;
    522368
    523         $fp = $this->FP;
    524         $buffer = $this->BUFFER;
    525 
    526         if(!empty($msgNum)) {
    527             $cmd = "UIDL $msgNum";
    528             $reply = $this->send_cmd($cmd);
    529             if(!$this->is_ok($reply))
    530             {
    531                 $this->ERROR = "POP3 uidl: " . _("Error ") . "[$reply]";
    532                 return false;
    533             }
    534             list ($ok,$num,$myUidl) = preg_split('/\s+/',$reply);
    535             return $myUidl;
    536         } else {
    537             $this->update_timer();
    538 
    539             $UIDLArray = array();
    540             $Total = $this->COUNT;
    541             $UIDLArray[0] = $Total;
    542 
    543             if ($Total < 1)
    544             {
    545                 return $UIDLArray;
    546             }
    547             $cmd = "UIDL";
    548             fwrite($fp, "UIDL\r\n");
    549             $reply = fgets($fp, $buffer);
    550             $reply = $this->strip_clf($reply);
    551             if($this->DEBUG) { @error_log("POP3 SEND [$cmd] GOT [$reply]",0); }
    552             if(!$this->is_ok($reply))
    553             {
    554                 $this->ERROR = "POP3 uidl: " . _("Error ") . "[$reply]";
    555                 return false;
    556             }
    557 
    558             $line = "";
    559             $count = 1;
    560             $line = fgets($fp,$buffer);
    561             while ( !ereg("^\.\r\n",$line)) {
    562                 if(ereg("^\.\r\n",$line)) {
    563                     break;
    564                 }
    565                 list ($msg,$msgUidl) = preg_split('/\s+/',$line);
    566                 $msgUidl = $this->strip_clf($msgUidl);
    567                 if($count == $msg) {
    568                     $UIDLArray[$msg] = $msgUidl;
    569                 }
    570                 else
    571                 {
    572                     $UIDLArray[$count] = 'deleted';
    573                 }
    574                 $count++;
    575                 $line = fgets($fp,$buffer);
    576             }
    577         }
    578         return $UIDLArray;
    579369    }
    580370
    581     function delete ($msgNum = "") {
    582         //  Flags a specified msg as deleted. The msg will not
    583         //  be deleted until a quit() method is called.
     371    /**
     372     * Checks the POP3 server response for +OK or -ERR
     373     *
     374     * @param string $string
     375     * @return boolean
     376     */
     377    function checkResponse ($string)
     378    {
     379      if (substr($string, 0, 3) !== '+OK')
     380      {
     381        $this->error = array(
     382          'error' => "Server reported an error: $string",
     383          'errno' => 0,
     384          'errstr' => ''
     385        );
    584386
    585         if(!isset($this->FP))
     387        if ($this->do_debug >= 1)
    586388        {
    587             $this->ERROR = "POP3 delete: " . _("No connection to server");
    588             return false;
     389          $this->displayErrors();
    589390        }
    590         if(empty($msgNum))
    591         {
    592             $this->ERROR = "POP3 delete: " . _("No msg number submitted");
    593             return false;
    594         }
    595         $reply = $this->send_cmd("DELE $msgNum");
    596         if(!$this->is_ok($reply))
    597         {
    598             $this->ERROR = "POP3 delete: " . _("Command failed ") . "[$reply]";
    599             return false;
    600         }
     391
     392        return false;
     393      }
     394      else
     395      {
    601396        return true;
    602     }
     397      }
    603398
    604     //  *********************************************************
    605 
    606     //  The following methods are internal to the class.
    607 
    608     function is_ok ($cmd = "") {
    609         //  Return true or false on +OK or -ERR
    610 
    611         if( empty($cmd) )
    612             return false;
    613         else
    614             return( ereg ("^\+OK", $cmd ) );
    615399    }
    616400
    617     function strip_clf ($text = "") {
    618         // Strips \r\n from server responses
     401    /**
     402     * If debug is enabled, display the error message array
     403     *
     404     */
     405    function displayErrors ()
     406    {
     407      echo '<pre>';
    619408
    620         if(empty($text))
    621             return $text;
    622         else {
    623             $stripped = str_replace("\r",'',$text);
    624             $stripped = str_replace("\n",'',$stripped);
    625             return $stripped;
    626         }
     409      foreach ($this->error as $single_error)
     410    {
     411        print_r($single_error);
    627412    }
    628413
    629     function parse_banner ( $server_text ) {
    630         $outside = true;
    631         $banner = "";
    632         $length = strlen($server_text);
    633         for($count =0; $count < $length; $count++)
    634         {
    635             $digit = substr($server_text,$count,1);
    636             if(!empty($digit))             {
    637                 if( (!$outside) && ($digit != '<') && ($digit != '>') )
    638                 {
    639                     $banner .= $digit;
    640                 }
    641                 if ($digit == '<')
    642                 {
    643                     $outside = false;
    644                 }
    645                 if($digit == '>')
    646                 {
    647                     $outside = true;
    648                 }
    649             }
    650         }
    651         $banner = $this->strip_clf($banner);    // Just in case
    652         return "<$banner>";
     414      echo '</pre>';
    653415    }
    654416
    655 }   // End class
     417  /**
     418   * Takes over from PHP for the socket warning handler
     419   *
     420   * @param integer $errno
     421   * @param string $errstr
     422   * @param string $errfile
     423   * @param integer $errline
     424   */
     425  function catchWarning ($errno, $errstr, $errfile, $errline)
     426  {
     427    $this->error[] = array(
     428      'error' => "Connecting to the POP3 server raised a PHP warning: ",
     429      'errno' => $errno,
     430      'errstr' => $errstr
     431    );
     432  }
     433
     434  //  End of class
     435}
    656436?>
  • wp-includes/class-phpmailer.php

     
    11<?php
    2 /**
    3  * PHPMailer - PHP email class
    4  *
    5  * Class for sending email using either sendmail, PHP mail(), or SMTP. Methods
    6  * are based upon the standard AspEmail(tm) classes.
    7  *
    8  * @copyright 2001 - 2003 Brent R. Matzelle
    9  * @license LGPL
    10  * @package PHPMailer
    11  */
     2/*~ class.phpmailer.php
     3.---------------------------------------------------------------------------.
     4|  Software: PHPMailer - PHP email class                                    |
     5|   Version: 2.0.2                                                          |
     6|   Contact: via sourceforge.net support pages (also www.codeworxtech.com)  |
     7|      Info: http://phpmailer.sourceforge.net                               |
     8|   Support: http://sourceforge.net/projects/phpmailer/                     |
     9| ------------------------------------------------------------------------- |
     10|    Author: Andy Prevost (project admininistrator)                         |
     11|    Author: Brent R. Matzelle (original founder)                           |
     12| Copyright (c) 2004-2007, Andy Prevost. All Rights Reserved.               |
     13| Copyright (c) 2001-2003, Brent R. Matzelle                                |
     14| ------------------------------------------------------------------------- |
     15|   License: Distributed under the Lesser General Public License (LGPL)     |
     16|            http://www.gnu.org/copyleft/lesser.html                        |
     17| This program is distributed in the hope that it will be useful - WITHOUT  |
     18| ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or     |
     19| FITNESS FOR A PARTICULAR PURPOSE.                                         |
     20| ------------------------------------------------------------------------- |
     21| We offer a number of paid services (www.codeworxtech.com):                |
     22| - Web Hosting on highly optimized fast and secure servers                 |
     23| - Technology Consulting                                                   |
     24| - Oursourcing (highly qualified programmers and graphic designers)        |
     25'---------------------------------------------------------------------------'
    1226
    1327/**
    1428 * PHPMailer - PHP email transport class
    1529 * @package PHPMailer
    16  * @author Brent R. Matzelle
    17  * @copyright 2001 - 2003 Brent R. Matzelle
     30 * @author Andy Prevost
     31 * @copyright 2004 - 2008 Andy Prevost
    1832 */
    19 class PHPMailer
    20 {
    21     /////////////////////////////////////////////////
    22     // PUBLIC VARIABLES
    23     /////////////////////////////////////////////////
    2433
    25     /**
    26      * Email priority (1 = High, 3 = Normal, 5 = low).
    27      * @var int
    28      */
    29     var $Priority          = 3;
     34class PHPMailer {
    3035
    31     /**
    32      * Sets the CharSet of the message.
    33      * @var string
    34      */
    35     var $CharSet           = "UTF-8";
     36  /////////////////////////////////////////////////
     37  // PROPERTIES, PUBLIC
     38  /////////////////////////////////////////////////
    3639
    37     /**
    38      * Sets the Content-type of the message.
    39      * @var string
    40      */
    41     var $ContentType        = "text/plain";
     40  /**
     41   * Email priority (1 = High, 3 = Normal, 5 = low).
     42   * @var int
     43   */
     44  var $Priority          = 3;
    4245
    43     /**
    44      * Sets the Encoding of the message. Options for this are "8bit",
    45      * "7bit", "binary", "base64", and "quoted-printable".
    46      * @var string
    47      */
    48     var $Encoding          = "8bit";
     46  /**
     47   * Sets the CharSet of the message.
     48   * @var string
     49   */
     50  var $CharSet           = 'iso-8859-1';
    4951
    50     /**
    51      * Holds the most recent mailer error message.
    52      * @var string
    53      */
    54     var $ErrorInfo         = "";
     52  /**
     53   * Sets the Content-type of the message.
     54   * @var string
     55   */
     56  var $ContentType        = 'text/plain';
    5557
    56     /**
    57      * Sets the From email address for the message.
    58      * @var string
    59      */
    60     var $From               = "localhost.localdomain";
     58  /**
     59   * Sets the Encoding of the message. Options for this are "8bit",
     60   * "7bit", "binary", "base64", and "quoted-printable".
     61   * @var string
     62   */
     63  var $Encoding          = '8bit';
    6164
    62     /**
    63      * Sets the From name of the message.
    64      * @var string
    65      */
    66     var $FromName           = "Support";
     65  /**
     66   * Holds the most recent mailer error message.
     67   * @var string
     68   */
     69  var $ErrorInfo         = '';
    6770
    68     /**
    69      * Sets the Sender email (Return-Path) of the message.  If not empty,
    70      * will be sent via -f to sendmail or as 'MAIL FROM' in smtp mode.
    71      * @var string
    72      */
    73     var $Sender            = "";
     71  /**
     72   * Sets the From email address for the message.
     73   * @var string
     74   */
     75  var $From              = 'root@localhost';
    7476
    75     /**
    76      * Sets the Subject of the message.
    77      * @var string
    78      */
    79     var $Subject           = "";
     77  /**
     78   * Sets the From name of the message.
     79   * @var string
     80   */
     81  var $FromName          = 'Root User';
    8082
    81     /**
    82      * Sets the Body of the message.  This can be either an HTML or text body.
    83      * If HTML then run IsHTML(true).
    84      * @var string
    85      */
    86     var $Body               = "";
     83  /**
     84   * Sets the Sender email (Return-Path) of the message.  If not empty,
     85   * will be sent via -f to sendmail or as 'MAIL FROM' in smtp mode.
     86   * @var string
     87   */
     88  var $Sender            = '';
    8789
    88     /**
    89      * Sets the text-only body of the message.  This automatically sets the
    90      * email to multipart/alternative.  This body can be read by mail
    91      * clients that do not have HTML email capability such as mutt. Clients
    92      * that can read HTML will view the normal Body.
    93      * @var string
    94      */
    95     var $AltBody           = "";
     90  /**
     91   * Sets the Subject of the message.
     92   * @var string
     93   */
     94  var $Subject           = '';
    9695
    97     /**
    98      * Sets word wrapping on the body of the message to a given number of
    99      * characters.
    100      * @var int
    101      */
    102     var $WordWrap          = 0;
     96  /**
     97   * Sets the Body of the message.  This can be either an HTML or text body.
     98   * If HTML then run IsHTML(true).
     99   * @var string
     100   */
     101  var $Body              = '';
    103102
    104     /**
    105      * Method to send mail: ("mail", "sendmail", or "smtp").
    106      * @var string
    107      */
    108     var $Mailer            = "mail";
     103  /**
     104   * Sets the text-only body of the message.  This automatically sets the
     105   * email to multipart/alternative.  This body can be read by mail
     106   * clients that do not have HTML email capability such as mutt. Clients
     107   * that can read HTML will view the normal Body.
     108   * @var string
     109   */
     110  var $AltBody           = '';
    109111
    110     /**
    111      * Sets the path of the sendmail program.
    112      * @var string
    113      */
    114     var $Sendmail          = "/usr/sbin/sendmail";
     112  /**
     113   * Sets word wrapping on the body of the message to a given number of
     114   * characters.
     115   * @var int
     116   */
     117  var $WordWrap          = 0;
    115118
    116     /**
    117      * Path to PHPMailer plugins.  This is now only useful if the SMTP class
    118      * is in a different directory than the PHP include path.
    119      * @var string
    120      */
    121     var $PluginDir         = "";
     119  /**
     120   * Method to send mail: ("mail", "sendmail", or "smtp").
     121   * @var string
     122   */
     123  var $Mailer            = 'mail';
    122124
    123     /**
    124      *  Holds PHPMailer version.
    125      * @var string
    126      */
    127     var $Version           = "1.73";
     125  /**
     126   * Sets the path of the sendmail program.
     127   * @var string
     128   */
     129  var $Sendmail          = '/usr/sbin/sendmail';
    128130
    129     /**
    130      * Sets the email address that a reading confirmation will be sent.
    131      * @var string
    132      */
    133     var $ConfirmReadingTo  = "";
     131  /**
     132   * Path to PHPMailer plugins.  This is now only useful if the SMTP class
     133   * is in a different directory than the PHP include path.
     134   * @var string
     135   */
     136  var $PluginDir         = '';
    134137
    135     /**
    136      *  Sets the hostname to use in Message-Id and Received headers
    137      *  and as default HELO string. If empty, the value returned
    138      *  by SERVER_NAME is used or 'localhost.localdomain'.
    139      *  @var string
    140      */
    141     var $Hostname          = "";
     138  /**
     139   * Holds PHPMailer version.
     140   * @var string
     141   */
     142  var $Version           = "2.0.2";
    142143
    143     /////////////////////////////////////////////////
    144     // SMTP VARIABLES
    145     /////////////////////////////////////////////////
     144  /**
     145   * Sets the email address that a reading confirmation will be sent.
     146   * @var string
     147   */
     148  var $ConfirmReadingTo  = '';
    146149
    147     /**
    148      *  Sets the SMTP hosts.  All hosts must be separated by a
    149      *  semicolon.  You can also specify a different port
    150      *  for each host by using this format: [hostname:port]
    151      *  (e.g. "smtp1.example.com:25;smtp2.example.com").
    152      *  Hosts will be tried in order.
    153      *  @var string
    154      */
    155     var $Host        = "localhost";
     150  /**
     151   * Sets the hostname to use in Message-Id and Received headers
     152   * and as default HELO string. If empty, the value returned
     153   * by SERVER_NAME is used or 'localhost.localdomain'.
     154   * @var string
     155   */
     156  var $Hostname          = '';
    156157
    157     /**
    158      *  Sets the default SMTP server port.
    159      *  @var int
    160      */
    161     var $Port        = 25;
     158  /**
     159   * Sets the message ID to be used in the Message-Id header.
     160   * If empty, a unique id will be generated.
     161   * @var string
     162   */
     163  var $MessageID         = '';
    162164
    163     /**
    164      *  Sets the SMTP HELO of the message (Default is $Hostname).
    165      *  @var string
    166      */
    167     var $Helo        = "";
     165  /////////////////////////////////////////////////
     166  // PROPERTIES FOR SMTP
     167  /////////////////////////////////////////////////
    168168
    169     /**
    170      *  Sets SMTP authentication. Utilizes the Username and Password variables.
    171      *  @var bool
    172      */
    173     var $SMTPAuth     = false;
     169  /**
     170   * Sets the SMTP hosts.  All hosts must be separated by a
     171   * semicolon.  You can also specify a different port
     172   * for each host by using this format: [hostname:port]
     173   * (e.g. "smtp1.example.com:25;smtp2.example.com").
     174   * Hosts will be tried in order.
     175   * @var string
     176   */
     177  var $Host        = 'localhost';
    174178
    175     /**
    176      *  Sets SMTP username.
    177      *  @var string
    178      */
    179     var $Username     = "";
     179  /**
     180   * Sets the default SMTP server port.
     181   * @var int
     182   */
     183  var $Port        = 25;
    180184
    181     /**
    182      *  Sets SMTP password.
    183      * @var string
    184      */
    185     var $Password     = "";
     185  /**
     186   * Sets the SMTP HELO of the message (Default is $Hostname).
     187   * @var string
     188   */
     189  var $Helo        = '';
    186190
    187     /**
    188      *  Sets the SMTP server timeout in seconds. This function will not
    189      *  work with the win32 version.
    190      *  @var int
    191      */
    192     var $Timeout      = 10;
     191  /**
     192   * Sets connection prefix.
     193   * Options are "", "ssl" or "tls"
     194   * @var string
     195   */
     196  var $SMTPSecure = "";
    193197
    194     /**
    195      *  Sets SMTP class debugging on or off.
    196      * @var bool
    197      */
    198     var $SMTPDebug    = false;
     198  /**
     199   * Sets SMTP authentication. Utilizes the Username and Password variables.
     200   * @var bool
     201   */
     202  var $SMTPAuth     = false;
    199203
    200     /**
    201      * Prevents the SMTP connection from being closed after each mail
    202      * sending.  If this is set to true then to close the connection
    203      * requires an explicit call to SmtpClose().
    204      * @var bool
    205      */
    206     var $SMTPKeepAlive = false;
     204  /**
     205   * Sets SMTP username.
     206   * @var string
     207   */
     208  var $Username     = '';
    207209
    208     /**#@+
    209      * @access private
    210      */
    211     var $smtp            = NULL;
    212     var $to              = array();
    213     var $cc              = array();
    214     var $bcc             = array();
    215     var $ReplyTo         = array();
    216     var $attachment      = array();
    217     var $CustomHeader    = array();
    218     var $message_type    = "";
    219     var $boundary        = array();
    220     var $language        = array();
    221     var $error_count     = 0;
    222     var $LE              = "\n";
    223     /**#@-*/
     210  /**
     211   * Sets SMTP password.
     212   * @var string
     213   */
     214  var $Password     = '';
    224215
    225     /////////////////////////////////////////////////
    226     // VARIABLE METHODS
    227     /////////////////////////////////////////////////
     216  /**
     217   * Sets the SMTP server timeout in seconds. This function will not
     218   * work with the win32 version.
     219   * @var int
     220   */
     221  var $Timeout      = 10;
    228222
    229     /**
    230      * Sets message type to HTML.
    231      * @param bool $bool
    232      * @return void
    233      */
    234     function IsHTML($bool) {
    235         if($bool == true)
    236             $this->ContentType = "text/html";
    237         else
    238             $this->ContentType = "text/plain";
    239     }
     223  /**
     224   * Sets SMTP class debugging on or off.
     225   * @var bool
     226   */
     227  var $SMTPDebug    = false;
    240228
    241     /**
    242      * Sets Mailer to send message using SMTP.
    243      * @return void
    244      */
    245     function IsSMTP() {
    246         $this->Mailer = "smtp";
    247     }
     229  /**
     230   * Prevents the SMTP connection from being closed after each mail
     231   * sending.  If this is set to true then to close the connection
     232   * requires an explicit call to SmtpClose().
     233   * @var bool
     234   */
     235  var $SMTPKeepAlive = false;
    248236
    249     /**
    250      * Sets Mailer to send message using PHP mail() function.
    251      * @return void
    252      */
    253     function IsMail() {
    254         $this->Mailer = "mail";
    255     }
     237  /**
     238   * Provides the ability to have the TO field process individual
     239   * emails, instead of sending to entire TO addresses
     240   * @var bool
     241   */
     242  var $SingleTo = false;
    256243
    257     /**
    258      * Sets Mailer to send message using the $Sendmail program.
    259      * @return void
    260      */
    261     function IsSendmail() {
    262         $this->Mailer = "sendmail";
    263     }
     244  /////////////////////////////////////////////////
     245  // PROPERTIES, PRIVATE
     246  /////////////////////////////////////////////////
    264247
    265     /**
    266      * Sets Mailer to send message using the qmail MTA.
    267      * @return void
    268      */
    269     function IsQmail() {
    270         $this->Sendmail = "/var/qmail/bin/sendmail";
    271         $this->Mailer = "sendmail";
    272     }
     248  var $smtp            = NULL;
     249  var $to              = array();
     250  var $cc              = array();
     251  var $bcc             = array();
     252  var $ReplyTo         = array();
     253  var $attachment      = array();
     254  var $CustomHeader    = array();
     255  var $message_type    = '';
     256  var $boundary        = array();
     257  var $language        = array();
     258  var $error_count     = 0;
     259  var $LE              = "\n";
     260  var $sign_key_file   = "";
     261  var $sign_key_pass   = "";
    273262
     263  /////////////////////////////////////////////////
     264  // METHODS, VARIABLES
     265  /////////////////////////////////////////////////
    274266
    275     /////////////////////////////////////////////////
    276     // RECIPIENT METHODS
    277     /////////////////////////////////////////////////
    278 
    279     /**
    280      * Adds a "To" address.
    281      * @param string $address
    282      * @param string $name
    283      * @return void
    284      */
    285     function AddAddress($address, $name = "") {
    286         $cur = count($this->to);
    287         $this->to[$cur][0] = trim($address);
    288         $this->to[$cur][1] = $name;
     267  /**
     268   * Sets message type to HTML.
     269   * @param bool $bool
     270   * @return void
     271   */
     272  function IsHTML($bool) {
     273    if($bool == true) {
     274      $this->ContentType = 'text/html';
     275    } else {
     276      $this->ContentType = 'text/plain';
    289277    }
     278  }
    290279
    291     /**
    292      * Adds a "Cc" address. Note: this function works
    293      * with the SMTP mailer on win32, not with the "mail"
    294      * mailer.
    295      * @param string $address
    296      * @param string $name
    297      * @return void
    298     */
    299     function AddCC($address, $name = "") {
    300         $cur = count($this->cc);
    301         $this->cc[$cur][0] = trim($address);
    302         $this->cc[$cur][1] = $name;
    303     }
     280  /**
     281   * Sets Mailer to send message using SMTP.
     282   * @return void
     283   */
     284  function IsSMTP() {
     285    $this->Mailer = 'smtp';
     286  }
    304287
    305     /**
    306      * Adds a "Bcc" address. Note: this function works
    307      * with the SMTP mailer on win32, not with the "mail"
    308      * mailer.
    309      * @param string $address
    310      * @param string $name
    311      * @return void
    312      */
    313     function AddBCC($address, $name = "") {
    314         $cur = count($this->bcc);
    315         $this->bcc[$cur][0] = trim($address);
    316         $this->bcc[$cur][1] = $name;
    317     }
     288  /**
     289   * Sets Mailer to send message using PHP mail() function.
     290   * @return void
     291   */
     292  function IsMail() {
     293    $this->Mailer = 'mail';
     294  }
    318295
    319     /**
    320      * Adds a "Reply-to" address.
    321      * @param string $address
    322      * @param string $name
    323      * @return void
    324      */
    325     function AddReplyTo($address, $name = "") {
    326         $cur = count($this->ReplyTo);
    327         $this->ReplyTo[$cur][0] = trim($address);
    328         $this->ReplyTo[$cur][1] = $name;
    329     }
     296  /**
     297   * Sets Mailer to send message using the $Sendmail program.
     298   * @return void
     299   */
     300  function IsSendmail() {
     301    $this->Mailer = 'sendmail';
     302  }
    330303
     304  /**
     305   * Sets Mailer to send message using the qmail MTA.
     306   * @return void
     307   */
     308  function IsQmail() {
     309    $this->Sendmail = '/var/qmail/bin/sendmail';
     310    $this->Mailer = 'sendmail';
     311  }
    331312
    332     /////////////////////////////////////////////////
    333     // MAIL SENDING METHODS
    334     /////////////////////////////////////////////////
     313  /////////////////////////////////////////////////
     314  // METHODS, RECIPIENTS
     315  /////////////////////////////////////////////////
    335316
    336     /**
    337      * Creates message and assigns Mailer. If the message is
    338      * not sent successfully then it returns false.  Use the ErrorInfo
    339      * variable to view description of the error.
    340      * @return bool
    341      */
    342     function Send() {
    343         $header = "";
    344         $body = "";
    345         $result = true;
     317  /**
     318   * Adds a "To" address.
     319   * @param string $address
     320   * @param string $name
     321   * @return void
     322   */
     323  function AddAddress($address, $name = '') {
     324    $cur = count($this->to);
     325    $this->to[$cur][0] = trim($address);
     326    $this->to[$cur][1] = $name;
     327  }
    346328
    347         if((count($this->to) + count($this->cc) + count($this->bcc)) < 1)
    348         {
    349             $this->SetError($this->Lang("provide_address"));
    350             return false;
    351         }
     329  /**
     330   * Adds a "Cc" address. Note: this function works
     331   * with the SMTP mailer on win32, not with the "mail"
     332   * mailer.
     333   * @param string $address
     334   * @param string $name
     335   * @return void
     336   */
     337  function AddCC($address, $name = '') {
     338    $cur = count($this->cc);
     339    $this->cc[$cur][0] = trim($address);
     340    $this->cc[$cur][1] = $name;
     341  }
    352342
    353         // Set whether the message is multipart/alternative
    354         if(!empty($this->AltBody))
    355             $this->ContentType = "multipart/alternative";
     343  /**
     344   * Adds a "Bcc" address. Note: this function works
     345   * with the SMTP mailer on win32, not with the "mail"
     346   * mailer.
     347   * @param string $address
     348   * @param string $name
     349   * @return void
     350   */
     351  function AddBCC($address, $name = '') {
     352    $cur = count($this->bcc);
     353    $this->bcc[$cur][0] = trim($address);
     354    $this->bcc[$cur][1] = $name;
     355  }
    356356
    357         $this->error_count = 0; // reset errors
    358         $this->SetMessageType();
    359         $header .= $this->CreateHeader();
    360         $body = $this->CreateBody();
     357  /**
     358   * Adds a "Reply-To" address.
     359   * @param string $address
     360   * @param string $name
     361   * @return void
     362   */
     363  function AddReplyTo($address, $name = '') {
     364    $cur = count($this->ReplyTo);
     365    $this->ReplyTo[$cur][0] = trim($address);
     366    $this->ReplyTo[$cur][1] = $name;
     367  }
    361368
    362         if($body == "") { return false; }
     369  /////////////////////////////////////////////////
     370  // METHODS, MAIL SENDING
     371  /////////////////////////////////////////////////
    363372
    364         // Choose the mailer
    365         switch($this->Mailer)
    366         {
    367             case "sendmail":
    368                 $result = $this->SendmailSend($header, $body);
    369                 break;
    370             case "mail":
    371                 $result = $this->MailSend($header, $body);
    372                 break;
    373             case "smtp":
    374                 $result = $this->SmtpSend($header, $body);
    375                 break;
    376             default:
    377             $this->SetError($this->Mailer . $this->Lang("mailer_not_supported"));
    378                 $result = false;
    379                 break;
    380         }
     373  /**
     374   * Creates message and assigns Mailer. If the message is
     375   * not sent successfully then it returns false.  Use the ErrorInfo
     376   * variable to view description of the error.
     377   * @return bool
     378   */
     379  function Send() {
     380    $header = '';
     381    $body = '';
     382    $result = true;
    381383
    382         return $result;
     384    if((count($this->to) + count($this->cc) + count($this->bcc)) < 1) {
     385      $this->SetError($this->Lang('provide_address'));
     386      return false;
    383387    }
    384388
    385     /**
    386      * Sends mail using the $Sendmail program.
    387      * @access private
    388      * @return bool
    389      */
    390     function SendmailSend($header, $body) {
    391         if ($this->Sender != "")
    392             $sendmail = sprintf("%s -oi -f %s -t", $this->Sendmail, escapeshellarg($this->Sender));
    393         else
    394             $sendmail = sprintf("%s -oi -t", $this->Sendmail);
     389    /* Set whether the message is multipart/alternative */
     390    if(!empty($this->AltBody)) {
     391      $this->ContentType = 'multipart/alternative';
     392    }
    395393
    396         if(!@$mail = popen($sendmail, "w"))
    397         {
    398             $this->SetError($this->Lang("execute") . $this->Sendmail);
    399             return false;
    400         }
     394    $this->error_count = 0; // reset errors
     395    $this->SetMessageType();
     396    $header .= $this->CreateHeader();
     397    $body = $this->CreateBody();
    401398
    402         fputs($mail, $header);
    403         fputs($mail, $body);
     399    if($body == '') {
     400      return false;
     401    }
    404402
    405         $result = pclose($mail) >> 8 & 0xFF;
    406         if($result != 0)
    407         {
    408             $this->SetError($this->Lang("execute") . $this->Sendmail);
    409             return false;
    410         }
    411 
    412         return true;
     403    /* Choose the mailer */
     404    switch($this->Mailer) {
     405      case 'sendmail':
     406        $result = $this->SendmailSend($header, $body);
     407        break;
     408      case 'smtp':
     409        $result = $this->SmtpSend($header, $body);
     410        break;
     411      case 'mail':
     412        $result = $this->MailSend($header, $body);
     413        break;
     414      default:
     415        $result = $this->MailSend($header, $body);
     416        break;
     417        //$this->SetError($this->Mailer . $this->Lang('mailer_not_supported'));
     418        //$result = false;
     419        //break;
    413420    }
    414421
    415     /**
    416      * Sends mail using the PHP mail() function.
    417      * @access private
    418      * @return bool
    419      */
    420     function MailSend($header, $body) {
    421         $to = "";
    422         for($i = 0; $i < count($this->to); $i++)
    423         {
    424             if($i != 0) { $to .= ", "; }
    425             $to .= $this->to[$i][0];
    426         }
     422    return $result;
     423  }
    427424
    428         if ($this->Sender != "" && strlen(ini_get("safe_mode"))< 1)
    429         {
    430             $old_from = ini_get("sendmail_from");
    431             ini_set("sendmail_from", $this->Sender);
    432             $params = sprintf("-oi -f %s", $this->Sender);
    433             $rt = @mail($to, $this->EncodeHeader($this->Subject), $body,
    434                         $header, $params);
    435         }
    436         else
    437             $rt = @mail($to, $this->EncodeHeader($this->Subject), $body, $header);
     425  /**
     426   * Sends mail using the $Sendmail program.
     427   * @access private
     428   * @return bool
     429   */
     430  function SendmailSend($header, $body) {
     431    if ($this->Sender != '') {
     432      $sendmail = sprintf("%s -oi -f %s -t", escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender));
     433    } else {
     434      $sendmail = sprintf("%s -oi -t", escapeshellcmd($this->Sendmail));
     435    }
    438436
    439         if (isset($old_from))
    440             ini_set("sendmail_from", $old_from);
     437    if(!@$mail = popen($sendmail, 'w')) {
     438      $this->SetError($this->Lang('execute') . $this->Sendmail);
     439      return false;
     440    }
    441441
    442         if(!$rt)
    443         {
    444             $this->SetError($this->Lang("instantiate"));
    445             return false;
    446         }
     442    fputs($mail, $header);
     443    fputs($mail, $body);
    447444
    448         return true;
     445    $result = pclose($mail);
     446    if (version_compare(phpversion(), '4.2.3') == -1) {
     447      $result = $result >> 8 & 0xFF;
    449448    }
     449    if($result != 0) {
     450      $this->SetError($this->Lang('execute') . $this->Sendmail);
     451      return false;
     452    }
     453    return true;
     454  }
    450455
    451     /**
    452      * Sends mail via SMTP using PhpSMTP (Author:
    453      * Chris Ryan).  Returns bool.  Returns false if there is a
    454      * bad MAIL FROM, RCPT, or DATA input.
    455      * @access private
    456      * @return bool
    457      */
    458     function SmtpSend($header, $body) {
    459         include_once($this->PluginDir . "class-smtp.php");
    460         $error = "";
    461         $bad_rcpt = array();
     456  /**
     457   * Sends mail using the PHP mail() function.
     458   * @access private
     459   * @return bool
     460   */
     461  function MailSend($header, $body) {
    462462
    463         if(!$this->SmtpConnect())
    464             return false;
     463    $to = '';
     464    for($i = 0; $i < count($this->to); $i++) {
     465      if($i != 0) { $to .= ', '; }
     466      $to .= $this->AddrFormat($this->to[$i]);
     467    }
    465468
    466         $smtp_from = ($this->Sender == "") ? $this->From : $this->Sender;
    467         if(!$this->smtp->Mail($smtp_from))
    468         {
    469             $error = $this->Lang("from_failed") . $smtp_from;
    470             $this->SetError($error);
    471             $this->smtp->Reset();
    472             return false;
    473         }
     469    $toArr = split(',', $to);
    474470
    475         // Attempt to send attach all recipients
    476         for($i = 0; $i < count($this->to); $i++)
    477         {
    478             if(!$this->smtp->Recipient($this->to[$i][0]))
    479                 $bad_rcpt[] = $this->to[$i][0];
     471    $params = sprintf("-oi -f %s", $this->Sender);
     472    if ($this->Sender != '' && strlen(ini_get('safe_mode')) < 1) {
     473      $old_from = ini_get('sendmail_from');
     474      ini_set('sendmail_from', $this->Sender);
     475      if ($this->SingleTo === true && count($toArr) > 1) {
     476        foreach ($toArr as $key => $val) {
     477          $rt = @mail($val, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header, $params);
    480478        }
    481         for($i = 0; $i < count($this->cc); $i++)
    482         {
    483             if(!$this->smtp->Recipient($this->cc[$i][0]))
    484                 $bad_rcpt[] = $this->cc[$i][0];
     479      } else {
     480        $rt = @mail($to, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header, $params);
     481      }
     482    } else {
     483      if ($this->SingleTo === true && count($toArr) > 1) {
     484        foreach ($toArr as $key => $val) {
     485          $rt = @mail($val, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header, $params);
    485486        }
    486         for($i = 0; $i < count($this->bcc); $i++)
    487         {
    488             if(!$this->smtp->Recipient($this->bcc[$i][0]))
    489                 $bad_rcpt[] = $this->bcc[$i][0];
    490         }
     487      } else {
     488        $rt = @mail($to, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header);
     489      }
     490    }
    491491
    492         if(count($bad_rcpt) > 0) // Create error message
    493         {
    494             for($i = 0; $i < count($bad_rcpt); $i++)
    495             {
    496                 if($i != 0) { $error .= ", "; }
    497                 $error .= $bad_rcpt[$i];
    498             }
    499             $error = $this->Lang("recipients_failed") . $error;
    500             $this->SetError($error);
    501             $this->smtp->Reset();
    502             return false;
    503         }
     492    if (isset($old_from)) {
     493      ini_set('sendmail_from', $old_from);
     494    }
    504495
    505         if(!$this->smtp->Data($header . $body))
    506         {
    507             $this->SetError($this->Lang("data_not_accepted"));
    508             $this->smtp->Reset();
    509             return false;
    510         }
    511         if($this->SMTPKeepAlive == true)
    512             $this->smtp->Reset();
    513         else
    514             $this->SmtpClose();
    515 
    516         return true;
     496    if(!$rt) {
     497      $this->SetError($this->Lang('instantiate'));
     498      return false;
    517499    }
    518500
    519     /**
    520      * Initiates a connection to an SMTP server.  Returns false if the
    521      * operation failed.
    522      * @access private
    523      * @return bool
    524      */
    525     function SmtpConnect() {
    526         if($this->smtp == NULL) { $this->smtp = new SMTP(); }
     501    return true;
     502  }
    527503
    528         $this->smtp->do_debug = $this->SMTPDebug;
    529         $hosts = explode(";", $this->Host);
    530         $index = 0;
    531         $connection = ($this->smtp->Connected());
     504  /**
     505   * Sends mail via SMTP using PhpSMTP (Author:
     506   * Chris Ryan).  Returns bool.  Returns false if there is a
     507   * bad MAIL FROM, RCPT, or DATA input.
     508   * @access private
     509   * @return bool
     510   */
     511  function SmtpSend($header, $body) {
     512    include_once($this->PluginDir . 'class.smtp.php');
     513    $error = '';
     514    $bad_rcpt = array();
    532515
    533         // Retry while there is no connection
    534         while($index < count($hosts) && $connection == false)
    535         {
    536             if(strstr($hosts[$index], ":"))
    537                 list($host, $port) = explode(":", $hosts[$index]);
    538             else
    539             {
    540                 $host = $hosts[$index];
    541                 $port = $this->Port;
    542             }
     516    if(!$this->SmtpConnect()) {
     517      return false;
     518    }
    543519
    544             if($this->smtp->Connect($host, $port, $this->Timeout))
    545             {
    546                 if ($this->Helo != '')
    547                     $this->smtp->Hello($this->Helo);
    548                 else
    549                     $this->smtp->Hello($this->ServerHostname());
     520    $smtp_from = ($this->Sender == '') ? $this->From : $this->Sender;
     521    if(!$this->smtp->Mail($smtp_from)) {
     522      $error = $this->Lang('from_failed') . $smtp_from;
     523      $this->SetError($error);
     524      $this->smtp->Reset();
     525      return false;
     526    }
    550527
    551                 if($this->SMTPAuth)
    552                 {
    553                     if(!$this->smtp->Authenticate($this->Username,
    554                                                   $this->Password))
    555                     {
    556                         $this->SetError($this->Lang("authenticate"));
    557                         $this->smtp->Reset();
    558                         $connection = false;
    559                     }
    560                 }
    561                 $connection = true;
    562             }
    563             $index++;
    564         }
    565         if(!$connection)
    566             $this->SetError($this->Lang("connect_host"));
    567 
    568         return $connection;
     528    /* Attempt to send attach all recipients */
     529    for($i = 0; $i < count($this->to); $i++) {
     530      if(!$this->smtp->Recipient($this->to[$i][0])) {
     531        $bad_rcpt[] = $this->to[$i][0];
     532      }
    569533    }
     534    for($i = 0; $i < count($this->cc); $i++) {
     535      if(!$this->smtp->Recipient($this->cc[$i][0])) {
     536        $bad_rcpt[] = $this->cc[$i][0];
     537      }
     538    }
     539    for($i = 0; $i < count($this->bcc); $i++) {
     540      if(!$this->smtp->Recipient($this->bcc[$i][0])) {
     541        $bad_rcpt[] = $this->bcc[$i][0];
     542      }
     543    }
    570544
    571     /**
    572      * Closes the active SMTP session if one exists.
    573      * @return void
    574      */
    575     function SmtpClose() {
    576         if($this->smtp != NULL)
    577         {
    578             if($this->smtp->Connected())
    579             {
    580                 $this->smtp->Quit();
    581                 $this->smtp->Close();
    582             }
     545    if(count($bad_rcpt) > 0) { // Create error message
     546      for($i = 0; $i < count($bad_rcpt); $i++) {
     547        if($i != 0) {
     548          $error .= ', ';
    583549        }
     550        $error .= $bad_rcpt[$i];
     551      }
     552      $error = $this->Lang('recipients_failed') . $error;
     553      $this->SetError($error);
     554      $this->smtp->Reset();
     555      return false;
    584556    }
    585557
    586     /**
    587      * Sets the language for all class error messages.  Returns false
    588      * if it cannot load the language file.  The default language type
    589      * is English.
    590      * @param string $lang_type Type of language (e.g. Portuguese: "br")
    591      * @param string $lang_path Path to the language file directory
    592      * @access public
    593      * @return bool
    594      */
    595     function SetLanguage($lang_type, $lang_path = "language/") {
    596         if(file_exists($lang_path.'phpmailer.lang-'.$lang_type.'.php'))
    597             include($lang_path.'phpmailer.lang-'.$lang_type.'.php');
    598         else if(file_exists($lang_path.'phpmailer.lang-en.php'))
    599             include($lang_path.'phpmailer.lang-en.php');
    600         else
    601         {
    602             $this->SetError("Could not load language file");
    603             return false;
    604         }
    605         $this->language = $PHPMAILER_LANG;
     558    if(!$this->smtp->Data($header . $body)) {
     559      $this->SetError($this->Lang('data_not_accepted'));
     560      $this->smtp->Reset();
     561      return false;
     562    }
     563    if($this->SMTPKeepAlive == true) {
     564      $this->smtp->Reset();
     565    } else {
     566      $this->SmtpClose();
     567    }
    606568
    607         return true;
     569    return true;
     570  }
     571
     572  /**
     573   * Initiates a connection to an SMTP server.  Returns false if the
     574   * operation failed.
     575   * @access private
     576   * @return bool
     577   */
     578  function SmtpConnect() {
     579    if($this->smtp == NULL) {
     580      $this->smtp = new SMTP();
    608581    }
    609582
    610     /////////////////////////////////////////////////
    611     // MESSAGE CREATION METHODS
    612     /////////////////////////////////////////////////
     583    $this->smtp->do_debug = $this->SMTPDebug;
     584    $hosts = explode(';', $this->Host);
     585    $index = 0;
     586    $connection = ($this->smtp->Connected());
    613587
    614     /**
    615      * Creates recipient headers.
    616      * @access private
    617      * @return string
    618      */
    619     function AddrAppend($type, $addr) {
    620         $addr_str = $type . ": ";
    621         $addr_str .= $this->AddrFormat($addr[0]);
    622         if(count($addr) > 1)
    623         {
    624             for($i = 1; $i < count($addr); $i++)
    625                 $addr_str .= ", " . $this->AddrFormat($addr[$i]);
     588    /* Retry while there is no connection */
     589    while($index < count($hosts) && $connection == false) {
     590      $hostinfo = array();
     591      if(eregi('^(.+):([0-9]+)$', $hosts[$index], $hostinfo)) {
     592        $host = $hostinfo[1];
     593        $port = $hostinfo[2];
     594      } else {
     595        $host = $hosts[$index];
     596        $port = $this->Port;
     597      }
     598
     599      if($this->smtp->Connect(((!empty($this->SMTPSecure))?$this->SMTPSecure.'://':'').$host, $port, $this->Timeout)) {
     600        if ($this->Helo != '') {
     601          $this->smtp->Hello($this->Helo);
     602        } else {
     603          $this->smtp->Hello($this->ServerHostname());
    626604        }
    627         $addr_str .= $this->LE;
    628605
    629         return $addr_str;
     606        $connection = true;
     607        if($this->SMTPAuth) {
     608          if(!$this->smtp->Authenticate($this->Username, $this->Password)) {
     609            $this->SetError($this->Lang('authenticate'));
     610            $this->smtp->Reset();
     611            $connection = false;
     612          }
     613        }
     614      }
     615      $index++;
    630616    }
     617    if(!$connection) {
     618      $this->SetError($this->Lang('connect_host'));
     619    }
    631620
    632     /**
    633      * Formats an address correctly.
    634      * @access private
    635      * @return string
    636      */
    637     function AddrFormat($addr) {
    638         if(empty($addr[1]))
    639             $formatted = $addr[0];
    640         else
    641         {
    642             $formatted = $this->EncodeHeader($addr[1], 'phrase') . " <" .
    643                          $addr[0] . ">";
    644         }
     621    return $connection;
     622  }
    645623
    646         return $formatted;
     624  /**
     625   * Closes the active SMTP session if one exists.
     626   * @return void
     627   */
     628  function SmtpClose() {
     629    if($this->smtp != NULL) {
     630      if($this->smtp->Connected()) {
     631        $this->smtp->Quit();
     632        $this->smtp->Close();
     633      }
    647634    }
     635  }
    648636
    649     /**
    650      * Wraps message for use with mailers that do not
    651      * automatically perform wrapping and for quoted-printable.
    652      * Original written by philippe.
    653      * @access private
    654      * @return string
    655      */
    656     function WrapText($message, $length, $qp_mode = false) {
    657         $soft_break = ($qp_mode) ? sprintf(" =%s", $this->LE) : $this->LE;
     637  /**
     638   * Sets the language for all class error messages.  Returns false
     639   * if it cannot load the language file.  The default language type
     640   * is English.
     641   * @param string $lang_type Type of language (e.g. Portuguese: "br")
     642   * @param string $lang_path Path to the language file directory
     643   * @access public
     644   * @return bool
     645   */
     646  function SetLanguage($lang_type, $lang_path = 'language/') {
     647    if(file_exists($lang_path.'phpmailer.lang-'.$lang_type.'.php')) {
     648      include($lang_path.'phpmailer.lang-'.$lang_type.'.php');
     649    } elseif (file_exists($lang_path.'phpmailer.lang-en.php')) {
     650      include($lang_path.'phpmailer.lang-en.php');
     651    } else {
     652      $this->SetError('Could not load language file');
     653      return false;
     654    }
     655    $this->language = $PHPMAILER_LANG;
    658656
    659         $message = $this->FixEOL($message);
    660         if (substr($message, -1) == $this->LE)
    661             $message = substr($message, 0, -1);
     657    return true;
     658  }
    662659
    663         $line = explode($this->LE, $message);
    664         $message = "";
    665         for ($i=0 ;$i < count($line); $i++)
    666         {
    667           $line_part = explode(" ", $line[$i]);
    668           $buf = "";
    669           for ($e = 0; $e<count($line_part); $e++)
    670           {
    671               $word = $line_part[$e];
    672               if ($qp_mode and (strlen($word) > $length))
    673               {
    674                 $space_left = $length - strlen($buf) - 1;
    675                 if ($e != 0)
    676                 {
    677                     if ($space_left > 20)
    678                     {
    679                         $len = $space_left;
    680                         if (substr($word, $len - 1, 1) == "=")
    681                           $len--;
    682                         elseif (substr($word, $len - 2, 1) == "=")
    683                           $len -= 2;
    684                         $part = substr($word, 0, $len);
    685                         $word = substr($word, $len);
    686                         $buf .= " " . $part;
    687                         $message .= $buf . sprintf("=%s", $this->LE);
    688                     }
    689                     else
    690                     {
    691                         $message .= $buf . $soft_break;
    692                     }
    693                     $buf = "";
    694                 }
    695                 while (strlen($word) > 0)
    696                 {
    697                     $len = $length;
    698                     if (substr($word, $len - 1, 1) == "=")
    699                         $len--;
    700                     elseif (substr($word, $len - 2, 1) == "=")
    701                         $len -= 2;
    702                     $part = substr($word, 0, $len);
    703                     $word = substr($word, $len);
     660  /////////////////////////////////////////////////
     661  // METHODS, MESSAGE CREATION
     662  /////////////////////////////////////////////////
    704663
    705                     if (strlen($word) > 0)
    706                         $message .= $part . sprintf("=%s", $this->LE);
    707                     else
    708                         $buf = $part;
    709                 }
    710               }
    711               else
    712               {
    713                 $buf_o = $buf;
    714                 $buf .= ($e == 0) ? $word : (" " . $word);
     664  /**
     665   * Creates recipient headers.
     666   * @access private
     667   * @return string
     668   */
     669  function AddrAppend($type, $addr) {
     670    $addr_str = $type . ': ';
     671    $addr_str .= $this->AddrFormat($addr[0]);
     672    if(count($addr) > 1) {
     673      for($i = 1; $i < count($addr); $i++) {
     674        $addr_str .= ', ' . $this->AddrFormat($addr[$i]);
     675      }
     676    }
     677    $addr_str .= $this->LE;
    715678
    716                 if (strlen($buf) > $length and $buf_o != "")
    717                 {
    718                     $message .= $buf_o . $soft_break;
    719                     $buf = $word;
    720                 }
    721               }
    722           }
    723           $message .= $buf . $this->LE;
    724         }
     679    return $addr_str;
     680  }
    725681
    726         return $message;
     682  /**
     683   * Formats an address correctly.
     684   * @access private
     685   * @return string
     686   */
     687  function AddrFormat($addr) {
     688    if(empty($addr[1])) {
     689      $formatted = $this->SecureHeader($addr[0]);
     690    } else {
     691      $formatted = $this->EncodeHeader($this->SecureHeader($addr[1]), 'phrase') . " <" . $this->SecureHeader($addr[0]) . ">";
    727692    }
    728693
    729     /**
    730      * Set the body wrapping.
    731      * @access private
    732      * @return void
    733      */
    734     function SetWordWrap() {
    735         if($this->WordWrap < 1)
    736             return;
     694    return $formatted;
     695  }
    737696
    738         switch($this->message_type)
    739         {
    740            case "alt":
    741               // fall through
    742            case "alt_attachments":
    743               $this->AltBody = $this->WrapText($this->AltBody, $this->WordWrap);
    744               break;
    745            default:
    746               $this->Body = $this->WrapText($this->Body, $this->WordWrap);
    747               break;
    748         }
     697  /**
     698   * Wraps message for use with mailers that do not
     699   * automatically perform wrapping and for quoted-printable.
     700   * Original written by philippe.
     701   * @access private
     702   * @return string
     703   */
     704  function WrapText($message, $length, $qp_mode = false) {
     705    $soft_break = ($qp_mode) ? sprintf(" =%s", $this->LE) : $this->LE;
     706    // If utf-8 encoding is used, we will need to make sure we don't
     707    // split multibyte characters when we wrap
     708    $is_utf8 = (strtolower($this->CharSet) == "utf-8");
     709
     710    $message = $this->FixEOL($message);
     711    if (substr($message, -1) == $this->LE) {
     712      $message = substr($message, 0, -1);
    749713    }
    750714
    751     /**
    752      * Assembles message header.
    753      * @access private
    754      * @return string
    755      */
    756     function CreateHeader() {
    757         $result = "";
     715    $line = explode($this->LE, $message);
     716    $message = '';
     717    for ($i=0 ;$i < count($line); $i++) {
     718      $line_part = explode(' ', $line[$i]);
     719      $buf = '';
     720      for ($e = 0; $e<count($line_part); $e++) {
     721        $word = $line_part[$e];
     722        if ($qp_mode and (strlen($word) > $length)) {
     723          $space_left = $length - strlen($buf) - 1;
     724          if ($e != 0) {
     725            if ($space_left > 20) {
     726              $len = $space_left;
     727              if ($is_utf8) {
     728                $len = $this->UTF8CharBoundary($word, $len);
     729              } elseif (substr($word, $len - 1, 1) == "=") {
     730                $len--;
     731              } elseif (substr($word, $len - 2, 1) == "=") {
     732                $len -= 2;
     733              }
     734              $part = substr($word, 0, $len);
     735              $word = substr($word, $len);
     736              $buf .= ' ' . $part;
     737              $message .= $buf . sprintf("=%s", $this->LE);
     738            } else {
     739              $message .= $buf . $soft_break;
     740            }
     741            $buf = '';
     742          }
     743          while (strlen($word) > 0) {
     744            $len = $length;
     745            if ($is_utf8) {
     746              $len = $this->UTF8CharBoundary($word, $len);
     747            } elseif (substr($word, $len - 1, 1) == "=") {
     748              $len--;
     749            } elseif (substr($word, $len - 2, 1) == "=") {
     750              $len -= 2;
     751            }
     752            $part = substr($word, 0, $len);
     753            $word = substr($word, $len);
    758754
    759         // Set the boundaries
    760         $uniq_id = md5(uniqid(time()));
    761         $this->boundary[1] = "b1_" . $uniq_id;
    762         $this->boundary[2] = "b2_" . $uniq_id;
     755            if (strlen($word) > 0) {
     756              $message .= $part . sprintf("=%s", $this->LE);
     757            } else {
     758              $buf = $part;
     759            }
     760          }
     761        } else {
     762          $buf_o = $buf;
     763          $buf .= ($e == 0) ? $word : (' ' . $word);
    763764
    764         $result .= $this->HeaderLine("Date", $this->RFCDate());
    765         if($this->Sender == "")
    766             $result .= $this->HeaderLine("Return-Path", trim($this->From));
    767         else
    768             $result .= $this->HeaderLine("Return-Path", trim($this->Sender));
    769 
    770         // To be created automatically by mail()
    771         if($this->Mailer != "mail")
    772         {
    773             if(count($this->to) > 0)
    774                 $result .= $this->AddrAppend("To", $this->to);
    775             else if (count($this->cc) == 0)
    776                 $result .= $this->HeaderLine("To", "undisclosed-recipients:;");
    777             if(count($this->cc) > 0)
    778                 $result .= $this->AddrAppend("Cc", $this->cc);
     765          if (strlen($buf) > $length and $buf_o != '') {
     766            $message .= $buf_o . $soft_break;
     767            $buf = $word;
     768          }
    779769        }
     770      }
     771      $message .= $buf . $this->LE;
     772    }
    780773
    781         $from = array();
    782         $from[0][0] = trim($this->From);
    783         $from[0][1] = $this->FromName;
    784         $result .= $this->AddrAppend("From", $from);
     774    return $message;
     775  }
    785776
    786         // sendmail and mail() extract Bcc from the header before sending
    787         if((($this->Mailer == "sendmail") || ($this->Mailer == "mail")) && (count($this->bcc) > 0))
    788             $result .= $this->AddrAppend("Bcc", $this->bcc);
     777  /**
     778   * Finds last character boundary prior to maxLength in a utf-8
     779   * quoted (printable) encoded string.
     780   * Original written by Colin Brown.
     781   * @access private
     782   * @param string $encodedText utf-8 QP text
     783   * @param int    $maxLength   find last character boundary prior to this length
     784   * @return int
     785   */
     786  function UTF8CharBoundary($encodedText, $maxLength) {
     787    $foundSplitPos = false;
     788    $lookBack = 3;
     789    while (!$foundSplitPos) {
     790      $lastChunk = substr($encodedText, $maxLength - $lookBack, $lookBack);
     791      $encodedCharPos = strpos($lastChunk, "=");
     792      if ($encodedCharPos !== false) {
     793        // Found start of encoded character byte within $lookBack block.
     794        // Check the encoded byte value (the 2 chars after the '=')
     795        $hex = substr($encodedText, $maxLength - $lookBack + $encodedCharPos + 1, 2);
     796        $dec = hexdec($hex);
     797        if ($dec < 128) { // Single byte character.
     798          // If the encoded char was found at pos 0, it will fit
     799          // otherwise reduce maxLength to start of the encoded char
     800          $maxLength = ($encodedCharPos == 0) ? $maxLength :
     801          $maxLength - ($lookBack - $encodedCharPos);
     802          $foundSplitPos = true;
     803        } elseif ($dec >= 192) { // First byte of a multi byte character
     804          // Reduce maxLength to split at start of character
     805          $maxLength = $maxLength - ($lookBack - $encodedCharPos);
     806          $foundSplitPos = true;
     807        } elseif ($dec < 192) { // Middle byte of a multi byte character, look further back
     808          $lookBack += 3;
     809        }
     810      } else {
     811        // No encoded character found
     812        $foundSplitPos = true;
     813      }
     814    }
     815    return $maxLength;
     816  }
    789817
    790         if(count($this->ReplyTo) > 0)
    791             $result .= $this->AddrAppend("Reply-to", $this->ReplyTo);
     818  /**
     819   * Set the body wrapping.
     820   * @access private
     821   * @return void
     822   */
     823  function SetWordWrap() {
     824    if($this->WordWrap < 1) {
     825      return;
     826    }
    792827
    793         // mail() sets the subject itself
    794         if($this->Mailer != "mail")
    795             $result .= $this->HeaderLine("Subject", $this->EncodeHeader(trim($this->Subject)));
     828    switch($this->message_type) {
     829      case 'alt':
     830        /* fall through */
     831      case 'alt_attachments':
     832        $this->AltBody = $this->WrapText($this->AltBody, $this->WordWrap);
     833        break;
     834      default:
     835        $this->Body = $this->WrapText($this->Body, $this->WordWrap);
     836        break;
     837    }
     838  }
    796839
    797         $result .= sprintf("Message-ID: <%s@%s>%s", $uniq_id, $this->ServerHostname(), $this->LE);
    798         $result .= $this->HeaderLine("X-Priority", $this->Priority);
     840  /**
     841   * Assembles message header.
     842   * @access private
     843   * @return string
     844   */
     845  function CreateHeader() {
     846    $result = '';
    799847
    800         if($this->ConfirmReadingTo != "")
    801         {
    802             $result .= $this->HeaderLine("Disposition-Notification-To",
    803                        "<" . trim($this->ConfirmReadingTo) . ">");
    804         }
     848    /* Set the boundaries */
     849    $uniq_id = md5(uniqid(time()));
     850    $this->boundary[1] = 'b1_' . $uniq_id;
     851    $this->boundary[2] = 'b2_' . $uniq_id;
    805852
    806         // Add custom headers
    807         for($index = 0; $index < count($this->CustomHeader); $index++)
    808         {
    809             $result .= $this->HeaderLine(trim($this->CustomHeader[$index][0]),
    810                        $this->EncodeHeader(trim($this->CustomHeader[$index][1])));
    811         }
    812         $result .= $this->HeaderLine("MIME-Version", "1.0");
     853    $result .= $this->HeaderLine('Date', $this->RFCDate());
     854    if($this->Sender == '') {
     855      $result .= $this->HeaderLine('Return-Path', trim($this->From));
     856    } else {
     857      $result .= $this->HeaderLine('Return-Path', trim($this->Sender));
     858    }
    813859
    814         switch($this->message_type)
    815         {
    816             case "plain":
    817                 $result .= $this->HeaderLine("Content-Transfer-Encoding", $this->Encoding);
    818                 $result .= sprintf("Content-Type: %s; charset=\"%s\"",
    819                                     $this->ContentType, $this->CharSet);
    820                 break;
    821             case "attachments":
    822                 // fall through
    823             case "alt_attachments":
    824                 if($this->InlineImageExists())
    825                 {
    826                     $result .= sprintf("Content-Type: %s;%s\ttype=\"text/html\";%s\tboundary=\"%s\"%s",
    827                                     "multipart/related", $this->LE, $this->LE,
    828                                     $this->boundary[1], $this->LE);
    829                 }
    830                 else
    831                 {
    832                     $result .= $this->HeaderLine("Content-Type", "multipart/mixed;");
    833                     $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"');
    834                 }
    835                 break;
    836             case "alt":
    837                 $result .= $this->HeaderLine("Content-Type", "multipart/alternative;");
    838                 $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"');
    839                 break;
    840         }
     860    /* To be created automatically by mail() */
     861    if($this->Mailer != 'mail') {
     862      if(count($this->to) > 0) {
     863        $result .= $this->AddrAppend('To', $this->to);
     864      } elseif (count($this->cc) == 0) {
     865        $result .= $this->HeaderLine('To', 'undisclosed-recipients:;');
     866      }
     867      if(count($this->cc) > 0) {
     868        $result .= $this->AddrAppend('Cc', $this->cc);
     869      }
     870    }
    841871
    842         if($this->Mailer != "mail")
    843             $result .= $this->LE.$this->LE;
     872    $from = array();
     873    $from[0][0] = trim($this->From);
     874    $from[0][1] = $this->FromName;
     875    $result .= $this->AddrAppend('From', $from);
    844876
    845         return $result;
     877    /* sendmail and mail() extract Cc from the header before sending */
     878    if((($this->Mailer == 'sendmail') || ($this->Mailer == 'mail')) && (count($this->cc) > 0)) {
     879      $result .= $this->AddrAppend('Cc', $this->cc);
    846880    }
    847881
    848     /**
    849      * Assembles the message body.  Returns an empty string on failure.
    850      * @access private
    851      * @return string
    852      */
    853     function CreateBody() {
    854         $result = "";
     882    /* sendmail and mail() extract Bcc from the header before sending */
     883    if((($this->Mailer == 'sendmail') || ($this->Mailer == 'mail')) && (count($this->bcc) > 0)) {
     884      $result .= $this->AddrAppend('Bcc', $this->bcc);
     885    }
    855886
    856         $this->SetWordWrap();
     887    if(count($this->ReplyTo) > 0) {
     888      $result .= $this->AddrAppend('Reply-To', $this->ReplyTo);
     889    }
    857890
    858         switch($this->message_type)
    859         {
    860             case "alt":
    861                 $result .= $this->GetBoundary($this->boundary[1], "",
    862                                               "text/plain", "");
    863                 $result .= $this->EncodeString($this->AltBody, $this->Encoding);
    864                 $result .= $this->LE.$this->LE;
    865                 $result .= $this->GetBoundary($this->boundary[1], "",
    866                                               "text/html", "");
     891    /* mail() sets the subject itself */
     892    if($this->Mailer != 'mail') {
     893      $result .= $this->HeaderLine('Subject', $this->EncodeHeader($this->SecureHeader($this->Subject)));
     894    }
    867895
    868                 $result .= $this->EncodeString($this->Body, $this->Encoding);
    869                 $result .= $this->LE.$this->LE;
     896    if($this->MessageID != '') {
     897      $result .= $this->HeaderLine('Message-ID',$this->MessageID);
     898    } else {
     899      $result .= sprintf("Message-ID: <%s@%s>%s", $uniq_id, $this->ServerHostname(), $this->LE);
     900    }
     901    $result .= $this->HeaderLine('X-Priority', $this->Priority);
     902    $result .= $this->HeaderLine('X-Mailer', 'PHPMailer (phpmailer.sourceforge.net) [version ' . $this->Version . ']');
    870903
    871                 $result .= $this->EndBoundary($this->boundary[1]);
    872                 break;
    873             case "plain":
    874                 $result .= $this->EncodeString($this->Body, $this->Encoding);
    875                 break;
    876             case "attachments":
    877                 $result .= $this->GetBoundary($this->boundary[1], "", "", "");
    878                 $result .= $this->EncodeString($this->Body, $this->Encoding);
    879                 $result .= $this->LE;
     904    if($this->ConfirmReadingTo != '') {
     905      $result .= $this->HeaderLine('Disposition-Notification-To', '<' . trim($this->ConfirmReadingTo) . '>');
     906    }
    880907
    881                 $result .= $this->AttachAll();
    882                 break;
    883             case "alt_attachments":
    884                 $result .= sprintf("--%s%s", $this->boundary[1], $this->LE);
    885                 $result .= sprintf("Content-Type: %s;%s" .
    886                                    "\tboundary=\"%s\"%s",
    887                                    "multipart/alternative", $this->LE,
    888                                    $this->boundary[2], $this->LE.$this->LE);
     908    // Add custom headers
     909    for($index = 0; $index < count($this->CustomHeader); $index++) {
     910      $result .= $this->HeaderLine(trim($this->CustomHeader[$index][0]), $this->EncodeHeader(trim($this->CustomHeader[$index][1])));
     911    }
     912    if (!$this->sign_key_file) {
     913      $result .= $this->HeaderLine('MIME-Version', '1.0');
     914      $result .= $this->GetMailMIME();
     915    }
    889916
    890                 // Create text body
    891                 $result .= $this->GetBoundary($this->boundary[2], "",
    892                                               "text/plain", "") . $this->LE;
     917    return $result;
     918  }
    893919
    894                 $result .= $this->EncodeString($this->AltBody, $this->Encoding);
    895                 $result .= $this->LE.$this->LE;
     920  /**
     921   * Returns the message MIME.
     922   * @access private
     923   * @return string
     924   */
     925  function GetMailMIME() {
     926    $result = '';
     927    switch($this->message_type) {
     928      case 'plain':
     929        $result .= $this->HeaderLine('Content-Transfer-Encoding', $this->Encoding);
     930        $result .= sprintf("Content-Type: %s; charset=\"%s\"", $this->ContentType, $this->CharSet);
     931        break;
     932      case 'attachments':
     933        /* fall through */
     934      case 'alt_attachments':
     935        if($this->InlineImageExists()){
     936          $result .= sprintf("Content-Type: %s;%s\ttype=\"text/html\";%s\tboundary=\"%s\"%s", 'multipart/related', $this->LE, $this->LE, $this->boundary[1], $this->LE);
     937        } else {
     938          $result .= $this->HeaderLine('Content-Type', 'multipart/mixed;');
     939          $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"');
     940        }
     941        break;
     942      case 'alt':
     943        $result .= $this->HeaderLine('Content-Type', 'multipart/alternative;');
     944        $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"');
     945        break;
     946    }
    896947
    897                 // Create the HTML body
    898                 $result .= $this->GetBoundary($this->boundary[2], "",
    899                                               "text/html", "") . $this->LE;
     948    if($this->Mailer != 'mail') {
     949      $result .= $this->LE.$this->LE;
     950    }
    900951
    901                 $result .= $this->EncodeString($this->Body, $this->Encoding);
    902                 $result .= $this->LE.$this->LE;
     952    return $result;
     953  }
    903954
    904                 $result .= $this->EndBoundary($this->boundary[2]);
     955  /**
     956   * Assembles the message body.  Returns an empty string on failure.
     957   * @access private
     958   * @return string
     959   */
     960  function CreateBody() {
     961    $result = '';
     962    if ($this->sign_key_file) {
     963      $result .= $this->GetMailMIME();
     964    }
    905965
    906                 $result .= $this->AttachAll();
    907                 break;
    908         }
    909         if($this->IsError())
    910             $result = "";
     966    $this->SetWordWrap();
    911967
    912         return $result;
     968    switch($this->message_type) {
     969      case 'alt':
     970        $result .= $this->GetBoundary($this->boundary[1], '', 'text/plain', '');
     971        $result .= $this->EncodeString($this->AltBody, $this->Encoding);
     972        $result .= $this->LE.$this->LE;
     973        $result .= $this->GetBoundary($this->boundary[1], '', 'text/html', '');
     974        $result .= $this->EncodeString($this->Body, $this->Encoding);
     975        $result .= $this->LE.$this->LE;
     976        $result .= $this->EndBoundary($this->boundary[1]);
     977        break;
     978      case 'plain':
     979        $result .= $this->EncodeString($this->Body, $this->Encoding);
     980        break;
     981      case 'attachments':
     982        $result .= $this->GetBoundary($this->boundary[1], '', '', '');
     983        $result .= $this->EncodeString($this->Body, $this->Encoding);
     984        $result .= $this->LE;
     985        $result .= $this->AttachAll();
     986        break;
     987      case 'alt_attachments':
     988        $result .= sprintf("--%s%s", $this->boundary[1], $this->LE);
     989        $result .= sprintf("Content-Type: %s;%s" . "\tboundary=\"%s\"%s", 'multipart/alternative', $this->LE, $this->boundary[2], $this->LE.$this->LE);
     990        $result .= $this->GetBoundary($this->boundary[2], '', 'text/plain', '') . $this->LE; // Create text body
     991        $result .= $this->EncodeString($this->AltBody, $this->Encoding);
     992        $result .= $this->LE.$this->LE;
     993        $result .= $this->GetBoundary($this->boundary[2], '', 'text/html', '') . $this->LE; // Create the HTML body
     994        $result .= $this->EncodeString($this->Body, $this->Encoding);
     995        $result .= $this->LE.$this->LE;
     996        $result .= $this->EndBoundary($this->boundary[2]);
     997        $result .= $this->AttachAll();
     998        break;
    913999    }
    9141000
    915     /**
    916      * Returns the start of a message boundary.
    917      * @access private
    918      */
    919     function GetBoundary($boundary, $charSet, $contentType, $encoding) {
    920         $result = "";
    921         if($charSet == "") { $charSet = $this->CharSet; }
    922         if($contentType == "") { $contentType = $this->ContentType; }
    923         if($encoding == "") { $encoding = $this->Encoding; }
     1001    if($this->IsError()) {
     1002      $result = '';
     1003    } else if ($this->sign_key_file) {
     1004      $file = tempnam("", "mail");
     1005      $fp = fopen($file, "w");
     1006      fwrite($fp, $result);
     1007      fclose($fp);
     1008      $signed = tempnam("", "signed");
    9241009
    925         $result .= $this->TextLine("--" . $boundary);
    926         $result .= sprintf("Content-Type: %s; charset = \"%s\"",
    927                             $contentType, $charSet);
    928         $result .= $this->LE;
    929         $result .= $this->HeaderLine("Content-Transfer-Encoding", $encoding);
    930         $result .= $this->LE;
     1010      if (@openssl_pkcs7_sign($file, $signed, "file://".$this->sign_key_file, array("file://".$this->sign_key_file, $this->sign_key_pass), null)) {
     1011        $fp = fopen($signed, "r");
     1012        $result = fread($fp, filesize($this->sign_key_file));
     1013        fclose($fp);
     1014      } else {
     1015        $this->SetError($this->Lang("signing").openssl_error_string());
     1016        $result = '';
     1017      }
    9311018
    932         return $result;
     1019      unlink($file);
     1020      unlink($signed);
    9331021    }
    9341022
    935     /**
    936      * Returns the end of a message boundary.
    937      * @access private
    938      */
    939     function EndBoundary($boundary) {
    940         return $this->LE . "--" . $boundary . "--" . $this->LE;
    941     }
     1023    return $result;
     1024  }
    9421025
    943     /**
    944      * Sets the message type.
    945      * @access private
    946      * @return void
    947      */
    948     function SetMessageType() {
    949         if(count($this->attachment) < 1 && strlen($this->AltBody) < 1)
    950             $this->message_type = "plain";
    951         else
    952         {
    953             if(count($this->attachment) > 0)
    954                 $this->message_type = "attachments";
    955             if(strlen($this->AltBody) > 0 && count($this->attachment) < 1)
    956                 $this->message_type = "alt";
    957             if(strlen($this->AltBody) > 0 && count($this->attachment) > 0)
    958                 $this->message_type = "alt_attachments";
    959         }
     1026  /**
     1027   * Returns the start of a message boundary.
     1028   * @access private
     1029   */
     1030  function GetBoundary($boundary, $charSet, $contentType, $encoding) {
     1031    $result = '';
     1032    if($charSet == '') {
     1033      $charSet = $this->CharSet;
    9601034    }
    961 
    962     /**
    963      * Returns a formatted header line.
    964      * @access private
    965      * @return string
    966      */
    967     function HeaderLine($name, $value) {
    968         return $name . ": " . $value . $this->LE;
     1035    if($contentType == '') {
     1036      $contentType = $this->ContentType;
    9691037    }
     1038    if($encoding == '') {
     1039      $encoding = $this->Encoding;
     1040    }
     1041    $result .= $this->TextLine('--' . $boundary);
     1042    $result .= sprintf("Content-Type: %s; charset = \"%s\"", $contentType, $charSet);
     1043    $result .= $this->LE;
     1044    $result .= $this->HeaderLine('Content-Transfer-Encoding', $encoding);
     1045    $result .= $this->LE;
    9701046
    971     /**
    972      * Returns a formatted mail line.
    973      * @access private
    974      * @return string
    975      */
    976     function TextLine($value) {
    977         return $value . $this->LE;
     1047    return $result;
     1048  }
     1049
     1050  /**
     1051   * Returns the end of a message boundary.
     1052   * @access private
     1053   */
     1054  function EndBoundary($boundary) {
     1055    return $this->LE . '--' . $boundary . '--' . $this->LE;
     1056  }
     1057
     1058  /**
     1059   * Sets the message type.
     1060   * @access private
     1061   * @return void
     1062   */
     1063  function SetMessageType() {
     1064    if(count($this->attachment) < 1 && strlen($this->AltBody) < 1) {
     1065      $this->message_type = 'plain';
     1066    } else {
     1067      if(count($this->attachment) > 0) {
     1068        $this->message_type = 'attachments';
     1069      }
     1070      if(strlen($this->AltBody) > 0 && count($this->attachment) < 1) {
     1071        $this->message_type = 'alt';
     1072      }
     1073      if(strlen($this->AltBody) > 0 && count($this->attachment) > 0) {
     1074        $this->message_type = 'alt_attachments';
     1075      }
    9781076    }
     1077  }
    9791078
    980     /////////////////////////////////////////////////
    981     // ATTACHMENT METHODS
    982     /////////////////////////////////////////////////
     1079  /* Returns a formatted header line.
     1080   * @access private
     1081   * @return string
     1082   */
     1083  function HeaderLine($name, $value) {
     1084    return $name . ': ' . $value . $this->LE;
     1085  }
    9831086
    984     /**
    985      * Adds an attachment from a path on the filesystem.
    986      * Returns false if the file could not be found
    987      * or accessed.
    988      * @param string $path Path to the attachment.
    989      * @param string $name Overrides the attachment name.
    990      * @param string $encoding File encoding (see $Encoding).
    991      * @param string $type File extension (MIME) type.
    992      * @return bool
    993      */
    994     function AddAttachment($path, $name = "", $encoding = "base64",
    995                            $type = "application/octet-stream") {
    996         if(!@is_file($path))
    997         {
    998             $this->SetError($this->Lang("file_access") . $path);
    999             return false;
    1000         }
     1087  /**
     1088   * Returns a formatted mail line.
     1089   * @access private
     1090   * @return string
     1091   */
     1092  function TextLine($value) {
     1093    return $value . $this->LE;
     1094  }
    10011095
    1002         $filename = basename($path);
    1003         if($name == "")
    1004             $name = $filename;
     1096  /////////////////////////////////////////////////
     1097  // CLASS METHODS, ATTACHMENTS
     1098  /////////////////////////////////////////////////
    10051099
    1006         $cur = count($this->attachment);
    1007         $this->attachment[$cur][0] = $path;
    1008         $this->attachment[$cur][1] = $filename;
    1009         $this->attachment[$cur][2] = $name;
    1010         $this->attachment[$cur][3] = $encoding;
    1011         $this->attachment[$cur][4] = $type;
    1012         $this->attachment[$cur][5] = false; // isStringAttachment
    1013         $this->attachment[$cur][6] = "attachment";
    1014         $this->attachment[$cur][7] = 0;
     1100  /**
     1101   * Adds an attachment from a path on the filesystem.
     1102   * Returns false if the file could not be found
     1103   * or accessed.
     1104   * @param string $path Path to the attachment.
     1105   * @param string $name Overrides the attachment name.
     1106   * @param string $encoding File encoding (see $Encoding).
     1107   * @param string $type File extension (MIME) type.
     1108   * @return bool
     1109   */
     1110  function AddAttachment($path, $name = '', $encoding = 'base64', $type = 'application/octet-stream') {
     1111    if(!@is_file($path)) {
     1112      $this->SetError($this->Lang('file_access') . $path);
     1113      return false;
     1114    }
    10151115
    1016         return true;
     1116    $filename = basename($path);
     1117    if($name == '') {
     1118      $name = $filename;
    10171119    }
    10181120
    1019     /**
    1020      * Attaches all fs, string, and binary attachments to the message.
    1021      * Returns an empty string on failure.
    1022      * @access private
    1023      * @return string
    1024      */
    1025     function AttachAll() {
    1026         // Return text of body
    1027         $mime = array();
     1121    $cur = count($this->attachment);
     1122    $this->attachment[$cur][0] = $path;
     1123    $this->attachment[$cur][1] = $filename;
     1124    $this->attachment[$cur][2] = $name;
     1125    $this->attachment[$cur][3] = $encoding;
     1126    $this->attachment[$cur][4] = $type;
     1127    $this->attachment[$cur][5] = false; // isStringAttachment
     1128    $this->attachment[$cur][6] = 'attachment';
     1129    $this->attachment[$cur][7] = 0;
    10281130
    1029         // Add all attachments
    1030         for($i = 0; $i < count($this->attachment); $i++)
    1031         {
    1032             // Check for string attachment
    1033             $bString = $this->attachment[$i][5];
    1034             if ($bString)
    1035                 $string = $this->attachment[$i][0];
    1036             else
    1037                 $path = $this->attachment[$i][0];
     1131    return true;
     1132  }
    10381133
    1039             $filename    = $this->attachment[$i][1];
    1040             $name        = $this->attachment[$i][2];
    1041             $encoding    = $this->attachment[$i][3];
    1042             $type        = $this->attachment[$i][4];
    1043             $disposition = $this->attachment[$i][6];
    1044             $cid         = $this->attachment[$i][7];
     1134  /**
     1135   * Attaches all fs, string, and binary attachments to the message.
     1136   * Returns an empty string on failure.
     1137   * @access private
     1138   * @return string
     1139   */
     1140  function AttachAll() {
     1141    /* Return text of body */
     1142    $mime = array();
    10451143
    1046             $mime[] = sprintf("--%s%s", $this->boundary[1], $this->LE);
    1047             $mime[] = sprintf("Content-Type: %s; name=\"%s\"%s", $type, $name, $this->LE);
    1048             $mime[] = sprintf("Content-Transfer-Encoding: %s%s", $encoding, $this->LE);
     1144    /* Add all attachments */
     1145    for($i = 0; $i < count($this->attachment); $i++) {
     1146      /* Check for string attachment */
     1147      $bString = $this->attachment[$i][5];
     1148      if ($bString) {
     1149        $string = $this->attachment[$i][0];
     1150      } else {
     1151        $path = $this->attachment[$i][0];
     1152      }
    10491153
    1050             if($disposition == "inline")
    1051                 $mime[] = sprintf("Content-ID: <%s>%s", $cid, $this->LE);
     1154      $filename    = $this->attachment[$i][1];
     1155      $name        = $this->attachment[$i][2];
     1156      $encoding    = $this->attachment[$i][3];
     1157      $type        = $this->attachment[$i][4];
     1158      $disposition = $this->attachment[$i][6];
     1159      $cid         = $this->attachment[$i][7];
    10521160
    1053             $mime[] = sprintf("Content-Disposition: %s; filename=\"%s\"%s",
    1054                               $disposition, $name, $this->LE.$this->LE);
     1161      $mime[] = sprintf("--%s%s", $this->boundary[1], $this->LE);
     1162      $mime[] = sprintf("Content-Type: %s; name=\"%s\"%s", $type, $name, $this->LE);
     1163      $mime[] = sprintf("Content-Transfer-Encoding: %s%s", $encoding, $this->LE);
    10551164
    1056             // Encode as string attachment
    1057             if($bString)
    1058             {
    1059                 $mime[] = $this->EncodeString($string, $encoding);
    1060                 if($this->IsError()) { return ""; }
    1061                 $mime[] = $this->LE.$this->LE;
    1062             }
    1063             else
    1064             {
    1065                 $mime[] = $this->EncodeFile($path, $encoding);
    1066                 if($this->IsError()) { return ""; }
    1067                 $mime[] = $this->LE.$this->LE;
    1068             }
    1069         }
     1165      if($disposition == 'inline') {
     1166        $mime[] = sprintf("Content-ID: <%s>%s", $cid, $this->LE);
     1167      }
    10701168
    1071         $mime[] = sprintf("--%s--%s", $this->boundary[1], $this->LE);
     1169      $mime[] = sprintf("Content-Disposition: %s; filename=\"%s\"%s", $disposition, $name, $this->LE.$this->LE);
    10721170
    1073         return join("", $mime);
     1171      /* Encode as string attachment */
     1172      if($bString) {
     1173        $mime[] = $this->EncodeString($string, $encoding);
     1174        if($this->IsError()) {
     1175          return '';
     1176        }
     1177        $mime[] = $this->LE.$this->LE;
     1178      } else {
     1179        $mime[] = $this->EncodeFile($path, $encoding);
     1180        if($this->IsError()) {
     1181          return '';
     1182        }
     1183        $mime[] = $this->LE.$this->LE;
     1184      }
    10741185    }
    10751186
    1076     /**
    1077      * Encodes attachment in requested format.  Returns an
    1078      * empty string on failure.
    1079      * @access private
    1080      * @return string
    1081      */
    1082     function EncodeFile ($path, $encoding = "base64") {
    1083         if(!@$fd = fopen($path, "rb"))
    1084         {
    1085             $this->SetError($this->Lang("file_open") . $path);
    1086             return "";
    1087         }
    1088         $magic_quotes = get_magic_quotes_runtime();
    1089         set_magic_quotes_runtime(0);
    1090         $file_buffer = fread($fd, filesize($path));
    1091         $file_buffer = $this->EncodeString($file_buffer, $encoding);
    1092         fclose($fd);
    1093         set_magic_quotes_runtime($magic_quotes);
     1187    $mime[] = sprintf("--%s--%s", $this->boundary[1], $this->LE);
    10941188
    1095         return $file_buffer;
     1189    return join('', $mime);
     1190  }
     1191
     1192  /**
     1193   * Encodes attachment in requested format.  Returns an
     1194   * empty string on failure.
     1195   * @access private
     1196   * @return string
     1197   */
     1198  function EncodeFile ($path, $encoding = 'base64') {
     1199    if(!@$fd = fopen($path, 'rb')) {
     1200      $this->SetError($this->Lang('file_open') . $path);
     1201      return '';
    10961202    }
     1203    $magic_quotes = get_magic_quotes_runtime();
     1204    set_magic_quotes_runtime(0);
     1205    $file_buffer = fread($fd, filesize($path));
     1206    $file_buffer = $this->EncodeString($file_buffer, $encoding);
     1207    fclose($fd);
     1208    set_magic_quotes_runtime($magic_quotes);
    10971209
    1098     /**
    1099      * Encodes string to requested format. Returns an
    1100      * empty string on failure.
    1101      * @access private
    1102      * @return string
    1103      */
    1104     function EncodeString ($str, $encoding = "base64") {
    1105         $encoded = "";
    1106         switch(strtolower($encoding)) {
    1107           case "base64":
    1108               // chunk_split is found in PHP >= 3.0.6
    1109               $encoded = chunk_split(base64_encode($str), 76, $this->LE);
    1110               break;
    1111           case "7bit":
    1112           case "8bit":
    1113               $encoded = $this->FixEOL($str);
    1114               if (substr($encoded, -(strlen($this->LE))) != $this->LE)
    1115                 $encoded .= $this->LE;
    1116               break;
    1117           case "binary":
    1118               $encoded = $str;
    1119               break;
    1120           case "quoted-printable":
    1121               $encoded = $this->EncodeQP($str);
    1122               break;
    1123           default:
    1124               $this->SetError($this->Lang("encoding") . $encoding);
    1125               break;
    1126         }
    1127         return $encoded;
     1210    return $file_buffer;
     1211  }
     1212
     1213  /**
     1214   * Encodes string to requested format. Returns an
     1215   * empty string on failure.
     1216   * @access private
     1217   * @return string
     1218   */
     1219  function EncodeString ($str, $encoding = 'base64') {
     1220    $encoded = '';
     1221    switch(strtolower($encoding)) {
     1222      case 'base64':
     1223        /* chunk_split is found in PHP >= 3.0.6 */
     1224        $encoded = chunk_split(base64_encode($str), 76, $this->LE);
     1225        break;
     1226      case '7bit':
     1227      case '8bit':
     1228        $encoded = $this->FixEOL($str);
     1229        if (substr($encoded, -(strlen($this->LE))) != $this->LE)
     1230          $encoded .= $this->LE;
     1231        break;
     1232      case 'binary':
     1233        $encoded = $str;
     1234        break;
     1235      case 'quoted-printable':
     1236        $encoded = $this->EncodeQP($str);
     1237        break;
     1238      default:
     1239        $this->SetError($this->Lang('encoding') . $encoding);
     1240        break;
    11281241    }
     1242    return $encoded;
     1243  }
    11291244
    1130     /**
    1131      * Encode a header string to best of Q, B, quoted or none.
    1132      * @access private
    1133      * @return string
    1134      */
    1135     function EncodeHeader ($str, $position = 'text') {
    1136       $x = 0;
     1245  /**
     1246   * Encode a header string to best of Q, B, quoted or none.
     1247   * @access private
     1248   * @return string
     1249   */
     1250  function EncodeHeader ($str, $position = 'text') {
     1251    $x = 0;
    11371252
    1138       switch (strtolower($position)) {
    1139         case 'phrase':
    1140           if (!preg_match('/[\200-\377]/', $str)) {
    1141             // Can't use addslashes as we don't know what value has magic_quotes_sybase.
    1142             $encoded = addcslashes($str, "\0..\37\177\\\"");
    1143 
    1144             if (($str == $encoded) && !preg_match('/[^A-Za-z0-9!#$%&\'*+\/=?^_`{|}~ -]/', $str))
    1145               return ($encoded);
    1146             else
    1147               return ("\"$encoded\"");
     1253    switch (strtolower($position)) {
     1254      case 'phrase':
     1255        if (!preg_match('/[\200-\377]/', $str)) {
     1256          /* Can't use addslashes as we don't know what value has magic_quotes_sybase. */
     1257          $encoded = addcslashes($str, "\0..\37\177\\\"");
     1258          if (($str == $encoded) && !preg_match('/[^A-Za-z0-9!#$%&\'*+\/=?^_`{|}~ -]/', $str)) {
     1259            return ($encoded);
     1260          } else {
     1261            return ("\"$encoded\"");
    11481262          }
    1149           $x = preg_match_all('/[^\040\041\043-\133\135-\176]/', $str, $matches);
    1150           break;
    1151         case 'comment':
    1152           $x = preg_match_all('/[()"]/', $str, $matches);
    1153           // Fall-through
    1154         case 'text':
    1155         default:
    1156           $x += preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $str, $matches);
    1157           break;
    1158       }
     1263        }
     1264        $x = preg_match_all('/[^\040\041\043-\133\135-\176]/', $str, $matches);
     1265        break;
     1266      case 'comment':
     1267        $x = preg_match_all('/[()"]/', $str, $matches);
     1268        /* Fall-through */
     1269      case 'text':
     1270      default:
     1271        $x += preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $str, $matches);
     1272        break;
     1273    }
    11591274
    1160       if ($x == 0)
    1161         return ($str);
     1275    if ($x == 0) {
     1276      return ($str);
     1277    }
    11621278
    1163       $maxlen = 75 - 7 - strlen($this->CharSet);
    1164       // Try to select the encoding which should produce the shortest output
    1165       if (strlen($str)/3 < $x) {
    1166         $encoding = 'B';
     1279    $maxlen = 75 - 7 - strlen($this->CharSet);
     1280    /* Try to select the encoding which should produce the shortest output */
     1281    if (strlen($str)/3 < $x) {
     1282      $encoding = 'B';
     1283      if (function_exists('mb_strlen') && $this->HasMultiBytes($str)) {
     1284     // Use a custom function which correctly encodes and wraps long
     1285     // multibyte strings without breaking lines within a character
     1286        $encoded = $this->Base64EncodeWrapMB($str);
     1287      } else {
    11671288        $encoded = base64_encode($str);
    11681289        $maxlen -= $maxlen % 4;
    11691290        $encoded = trim(chunk_split($encoded, $maxlen, "\n"));
    1170       } else {
    1171         $encoding = 'Q';
    1172         $encoded = $this->EncodeQ($str, $position);
    1173         $encoded = $this->WrapText($encoded, $maxlen, true);
    1174         $encoded = str_replace("=".$this->LE, "\n", trim($encoded));
    11751291      }
     1292    } else {
     1293      $encoding = 'Q';
     1294      $encoded = $this->EncodeQ($str, $position);
     1295      $encoded = $this->WrapText($encoded, $maxlen, true);
     1296      $encoded = str_replace('='.$this->LE, "\n", trim($encoded));
     1297    }
    11761298
    1177       $encoded = preg_replace('/^(.*)$/m', " =?".$this->CharSet."?$encoding?\\1?=", $encoded);
    1178       $encoded = trim(str_replace("\n", $this->LE, $encoded));
     1299    $encoded = preg_replace('/^(.*)$/m', " =?".$this->CharSet."?$encoding?\\1?=", $encoded);
     1300    $encoded = trim(str_replace("\n", $this->LE, $encoded));
    11791301
    1180       return $encoded;
     1302    return $encoded;
     1303  }
     1304
     1305  /**
     1306   * Checks if a string contains multibyte characters.
     1307   * @access private
     1308   * @param string $str multi-byte text to wrap encode
     1309   * @return bool
     1310   */
     1311  function HasMultiBytes($str) {
     1312    if (function_exists('mb_strlen')) {
     1313      return (strlen($str) > mb_strlen($str, $this->CharSet));
     1314    } else { // Assume no multibytes (we can't handle without mbstring functions anyway)
     1315      return False;
    11811316    }
     1317  }
    11821318
    1183     /**
    1184      * Encode string to quoted-printable.
    1185      * @access private
    1186      * @return string
    1187      */
    1188     function EncodeQP ($str) {
    1189         $encoded = $this->FixEOL($str);
    1190         if (substr($encoded, -(strlen($this->LE))) != $this->LE)
    1191             $encoded .= $this->LE;
     1319  /**
     1320   * Correctly encodes and wraps long multibyte strings for mail headers
     1321   * without breaking lines within a character.
     1322   * Adapted from a function by paravoid at http://uk.php.net/manual/en/function.mb-encode-mimeheader.php
     1323   * @access private
     1324   * @param string $str multi-byte text to wrap encode
     1325   * @return string
     1326   */
     1327  function Base64EncodeWrapMB($str) {
     1328    $start = "=?".$this->CharSet."?B?";
     1329    $end = "?=";
     1330    $encoded = "";
    11921331
    1193         // Replace every high ascii, control and = characters
    1194         $encoded = preg_replace('/([\000-\010\013\014\016-\037\075\177-\377])/e',
    1195                   "'='.sprintf('%02X', ord('\\1'))", $encoded);
    1196         // Replace every spaces and tabs when it's the last character on a line
    1197         $encoded = preg_replace("/([\011\040])".$this->LE."/e",
    1198                   "'='.sprintf('%02X', ord('\\1')).'".$this->LE."'", $encoded);
     1332    $mb_length = mb_strlen($str, $this->CharSet);
     1333    // Each line must have length <= 75, including $start and $end
     1334    $length = 75 - strlen($start) - strlen($end);
     1335    // Average multi-byte ratio
     1336    $ratio = $mb_length / strlen($str);
     1337    // Base64 has a 4:3 ratio
     1338    $offset = $avgLength = floor($length * $ratio * .75);
    11991339
    1200         // Maximum line length of 76 characters before CRLF (74 + space + '=')
    1201         $encoded = $this->WrapText($encoded, 74, true);
     1340    for ($i = 0; $i < $mb_length; $i += $offset) {
     1341      $lookBack = 0;
    12021342
    1203         return $encoded;
     1343      do {
     1344        $offset = $avgLength - $lookBack;
     1345        $chunk = mb_substr($str, $i, $offset, $this->CharSet);
     1346        $chunk = base64_encode($chunk);
     1347        $lookBack++;
     1348      }
     1349      while (strlen($chunk) > $length);
     1350
     1351      $encoded .= $chunk . $this->LE;
    12041352    }
    12051353
    1206     /**
    1207      * Encode string to q encoding.
    1208      * @access private
    1209      * @return string
    1210      */
    1211     function EncodeQ ($str, $position = "text") {
    1212         // There should not be any EOL in the string
    1213         $encoded = preg_replace("[\r\n]", "", $str);
     1354    // Chomp the last linefeed
     1355    $encoded = substr($encoded, 0, -strlen($this->LE));
     1356    return $encoded;
     1357  }
    12141358
    1215         switch (strtolower($position)) {
    1216           case "phrase":
    1217             $encoded = preg_replace("/([^A-Za-z0-9!*+\/ -])/e", "'='.sprintf('%02X', ord('\\1'))", $encoded);
    1218             break;
    1219           case "comment":
    1220             $encoded = preg_replace("/([\(\)\"])/e", "'='.sprintf('%02X', ord('\\1'))", $encoded);
    1221           case "text":
    1222           default:
    1223             // Replace every high ascii, control =, ? and _ characters
    1224             $encoded = preg_replace('/([\000-\011\013\014\016-\037\075\077\137\177-\377])/e',
    1225                   "'='.sprintf('%02X', ord('\\1'))", $encoded);
    1226             break;
     1359  /**
     1360   * Encode string to quoted-printable.
     1361   * @access private
     1362   * @return string
     1363   */
     1364  function EncodeQP( $input = '', $line_max = 76, $space_conv = false ) {
     1365    $hex = array('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F');
     1366    $lines = preg_split('/(?:\r\n|\r|\n)/', $input);
     1367    $eol = "\r\n";
     1368    $escape = '=';
     1369    $output = '';
     1370    while( list(, $line) = each($lines) ) {
     1371      $linlen = strlen($line);
     1372      $newline = '';
     1373      for($i = 0; $i < $linlen; $i++) {
     1374        $c = substr( $line, $i, 1 );
     1375        $dec = ord( $c );
     1376        if ( ( $i == 0 ) && ( $dec == 46 ) ) { // convert first point in the line into =2E
     1377          $c = '=2E';
    12271378        }
     1379        if ( $dec == 32 ) {
     1380          if ( $i == ( $linlen - 1 ) ) { // convert space at eol only
     1381            $c = '=20';
     1382          } else if ( $space_conv ) {
     1383            $c = '=20';
     1384          }
     1385        } elseif ( ($dec == 61) || ($dec < 32 ) || ($dec > 126) ) { // always encode "\t", which is *not* required
     1386          $h2 = floor($dec/16);
     1387          $h1 = floor($dec%16);
     1388          $c = $escape.$hex[$h2].$hex[$h1];
     1389        }
     1390        if ( (strlen($newline) + strlen($c)) >= $line_max ) { // CRLF is not counted
     1391          $output .= $newline.$escape.$eol; //  soft line break; " =\r\n" is okay
     1392          $newline = '';
     1393          // check if newline first character will be point or not
     1394          if ( $dec == 46 ) {
     1395            $c = '=2E';
     1396          }
     1397        }
     1398        $newline .= $c;
     1399      } // end of for
     1400      $output .= $newline.$eol;
     1401    } // end of while
     1402    return trim($output);
     1403  }
    12281404
    1229         // Replace every spaces to _ (more readable than =20)
    1230         $encoded = str_replace(" ", "_", $encoded);
     1405  /**
     1406   * Encode string to q encoding.
     1407   * @access private
     1408   * @return string
     1409   */
     1410  function EncodeQ ($str, $position = 'text') {
     1411    /* There should not be any EOL in the string */
     1412    $encoded = preg_replace("[\r\n]", '', $str);
    12311413
    1232         return $encoded;
     1414    switch (strtolower($position)) {
     1415      case 'phrase':
     1416        $encoded = preg_replace("/([^A-Za-z0-9!*+\/ -])/e", "'='.sprintf('%02X', ord('\\1'))", $encoded);
     1417        break;
     1418      case 'comment':
     1419        $encoded = preg_replace("/([\(\)\"])/e", "'='.sprintf('%02X', ord('\\1'))", $encoded);
     1420      case 'text':
     1421      default:
     1422        /* Replace every high ascii, control =, ? and _ characters */
     1423        $encoded = preg_replace('/([\000-\011\013\014\016-\037\075\077\137\177-\377])/e',
     1424              "'='.sprintf('%02X', ord('\\1'))", $encoded);
     1425        break;
    12331426    }
    12341427
    1235     /**
    1236      * Adds a string or binary attachment (non-filesystem) to the list.
    1237      * This method can be used to attach ascii or binary data,
    1238      * such as a BLOB record from a database.
    1239      * @param string $string String attachment data.
    1240      * @param string $filename Name of the attachment.
    1241      * @param string $encoding File encoding (see $Encoding).
    1242      * @param string $type File extension (MIME) type.
    1243      * @return void
    1244      */
    1245     function AddStringAttachment($string, $filename, $encoding = "base64",
    1246                                  $type = "application/octet-stream") {
    1247         // Append to $attachment array
    1248         $cur = count($this->attachment);
    1249         $this->attachment[$cur][0] = $string;
    1250         $this->attachment[$cur][1] = $filename;
    1251         $this->attachment[$cur][2] = $filename;
    1252         $this->attachment[$cur][3] = $encoding;
    1253         $this->attachment[$cur][4] = $type;
    1254         $this->attachment[$cur][5] = true; // isString
    1255         $this->attachment[$cur][6] = "attachment";
    1256         $this->attachment[$cur][7] = 0;
    1257     }
     1428    /* Replace every spaces to _ (more readable than =20) */
     1429    $encoded = str_replace(' ', '_', $encoded);
    12581430
    1259     /**
    1260      * Adds an embedded attachment.  This can include images, sounds, and
    1261      * just about any other document.  Make sure to set the $type to an
    1262      * image type.  For JPEG images use "image/jpeg" and for GIF images
    1263      * use "image/gif".
    1264      * @param string $path Path to the attachment.
    1265      * @param string $cid Content ID of the attachment.  Use this to identify
    1266      *        the Id for accessing the image in an HTML form.
    1267      * @param string $name Overrides the attachment name.
    1268      * @param string $encoding File encoding (see $Encoding).
    1269      * @param string $type File extension (MIME) type.
    1270      * @return bool
    1271      */
    1272     function AddEmbeddedImage($path, $cid, $name = "", $encoding = "base64",
    1273                               $type = "application/octet-stream") {
     1431    return $encoded;
     1432  }
    12741433
    1275         if(!@is_file($path))
    1276         {
    1277             $this->SetError($this->Lang("file_access") . $path);
    1278             return false;
    1279         }
     1434  /**
     1435   * Adds a string or binary attachment (non-filesystem) to the list.
     1436   * This method can be used to attach ascii or binary data,
     1437   * such as a BLOB record from a database.
     1438   * @param string $string String attachment data.
     1439   * @param string $filename Name of the attachment.
     1440   * @param string $encoding File encoding (see $Encoding).
     1441   * @param string $type File extension (MIME) type.
     1442   * @return void
     1443   */
     1444  function AddStringAttachment($string, $filename, $encoding = 'base64', $type = 'application/octet-stream') {
     1445    /* Append to $attachment array */
     1446    $cur = count($this->attachment);
     1447    $this->attachment[$cur][0] = $string;
     1448    $this->attachment[$cur][1] = $filename;
     1449    $this->attachment[$cur][2] = $filename;
     1450    $this->attachment[$cur][3] = $encoding;
     1451    $this->attachment[$cur][4] = $type;
     1452    $this->attachment[$cur][5] = true; // isString
     1453    $this->attachment[$cur][6] = 'attachment';
     1454    $this->attachment[$cur][7] = 0;
     1455  }
    12801456
    1281         $filename = basename($path);
    1282         if($name == "")
    1283             $name = $filename;
     1457  /**
     1458   * Adds an embedded attachment.  This can include images, sounds, and
     1459   * just about any other document.  Make sure to set the $type to an
     1460   * image type.  For JPEG images use "image/jpeg" and for GIF images
     1461   * use "image/gif".
     1462   * @param string $path Path to the attachment.
     1463   * @param string $cid Content ID of the attachment.  Use this to identify
     1464   *        the Id for accessing the image in an HTML form.
     1465   * @param string $name Overrides the attachment name.
     1466   * @param string $encoding File encoding (see $Encoding).
     1467   * @param string $type File extension (MIME) type.
     1468   * @return bool
     1469   */
     1470  function AddEmbeddedImage($path, $cid, $name = '', $encoding = 'base64', $type = 'application/octet-stream') {
    12841471
    1285         // Append to $attachment array
    1286         $cur = count($this->attachment);
    1287         $this->attachment[$cur][0] = $path;
    1288         $this->attachment[$cur][1] = $filename;
    1289         $this->attachment[$cur][2] = $name;
    1290         $this->attachment[$cur][3] = $encoding;
    1291         $this->attachment[$cur][4] = $type;
    1292         $this->attachment[$cur][5] = false; // isStringAttachment
    1293         $this->attachment[$cur][6] = "inline";
    1294         $this->attachment[$cur][7] = $cid;
     1472    if(!@is_file($path)) {
     1473      $this->SetError($this->Lang('file_access') . $path);
     1474      return false;
     1475    }
    12951476
    1296         return true;
     1477    $filename = basename($path);
     1478    if($name == '') {
     1479      $name = $filename;
    12971480    }
    12981481
    1299     /**
    1300      * Returns true if an inline attachment is present.
    1301      * @access private
    1302      * @return bool
    1303      */
    1304     function InlineImageExists() {
    1305         $result = false;
    1306         for($i = 0; $i < count($this->attachment); $i++)
    1307         {
    1308             if($this->attachment[$i][6] == "inline")
    1309             {
    1310                 $result = true;
    1311                 break;
    1312             }
    1313         }
     1482    /* Append to $attachment array */
     1483    $cur = count($this->attachment);
     1484    $this->attachment[$cur][0] = $path;
     1485    $this->attachment[$cur][1] = $filename;
     1486    $this->attachment[$cur][2] = $name;
     1487    $this->attachment[$cur][3] = $encoding;
     1488    $this->attachment[$cur][4] = $type;
     1489    $this->attachment[$cur][5] = false;
     1490    $this->attachment[$cur][6] = 'inline';
     1491    $this->attachment[$cur][7] = $cid;
    13141492
    1315         return $result;
     1493    return true;
     1494  }
     1495
     1496  /**
     1497   * Returns true if an inline attachment is present.
     1498   * @access private
     1499   * @return bool
     1500   */
     1501  function InlineImageExists() {
     1502    $result = false;
     1503    for($i = 0; $i < count($this->attachment); $i++) {
     1504      if($this->attachment[$i][6] == 'inline') {
     1505        $result = true;
     1506        break;
     1507      }
    13161508    }
    13171509
    1318     /////////////////////////////////////////////////
    1319     // MESSAGE RESET METHODS
    1320     /////////////////////////////////////////////////
     1510    return $result;
     1511  }
    13211512
    1322     /**
    1323      * Clears all recipients assigned in the TO array.  Returns void.
    1324      * @return void
    1325      */
    1326     function ClearAddresses() {
    1327         $this->to = array();
    1328     }
     1513  /////////////////////////////////////////////////
     1514  // CLASS METHODS, MESSAGE RESET
     1515  /////////////////////////////////////////////////
    13291516
    1330     /**
    1331      * Clears all recipients assigned in the CC array.  Returns void.
    1332      * @return void
    1333      */
    1334     function ClearCCs() {
    1335         $this->cc = array();
    1336     }
     1517  /**
     1518   * Clears all recipients assigned in the TO array.  Returns void.
     1519   * @return void
     1520   */
     1521  function ClearAddresses() {
     1522    $this->to = array();
     1523  }
    13371524
    1338     /**
    1339      * Clears all recipients assigned in the BCC array.  Returns void.
    1340      * @return void
    1341      */
    1342     function ClearBCCs() {
    1343         $this->bcc = array();
    1344     }
     1525  /**
     1526   * Clears all recipients assigned in the CC array.  Returns void.
     1527   * @return void
     1528   */
     1529  function ClearCCs() {
     1530    $this->cc = array();
     1531  }
    13451532
    1346     /**
    1347      * Clears all recipients assigned in the ReplyTo array.  Returns void.
    1348      * @return void
    1349      */
    1350     function ClearReplyTos() {
    1351         $this->ReplyTo = array();
    1352     }
     1533  /**
     1534   * Clears all recipients assigned in the BCC array.  Returns void.
     1535   * @return void
     1536   */
     1537  function ClearBCCs() {
     1538    $this->bcc = array();
     1539  }
    13531540
    1354     /**
    1355      * Clears all recipients assigned in the TO, CC and BCC
    1356      * array.  Returns void.
    1357      * @return void
    1358      */
    1359     function ClearAllRecipients() {
    1360         $this->to = array();
    1361         $this->cc = array();
    1362         $this->bcc = array();
    1363     }
     1541  /**
     1542   * Clears all recipients assigned in the ReplyTo array.  Returns void.
     1543   * @return void
     1544   */
     1545  function ClearReplyTos() {
     1546    $this->ReplyTo = array();
     1547  }
    13641548
    1365     /**
    1366      * Clears all previously set filesystem, string, and binary
    1367      * attachments.  Returns void.
    1368      * @return void
    1369      */
    1370     function ClearAttachments() {
    1371         $this->attachment = array();
    1372     }
     1549  /**
     1550   * Clears all recipients assigned in the TO, CC and BCC
     1551   * array.  Returns void.
     1552   * @return void
     1553   */
     1554  function ClearAllRecipients() {
     1555    $this->to = array();
     1556    $this->cc = array();
     1557    $this->bcc = array();
     1558  }
    13731559
    1374     /**
    1375      * Clears all custom headers.  Returns void.
    1376      * @return void
    1377      */
    1378     function ClearCustomHeaders() {
    1379         $this->CustomHeader = array();
    1380     }
     1560  /**
     1561   * Clears all previously set filesystem, string, and binary
     1562   * attachments.  Returns void.
     1563   * @return void
     1564   */
     1565  function ClearAttachments() {
     1566    $this->attachment = array();
     1567  }
    13811568
     1569  /**
     1570   * Clears all custom headers.  Returns void.
     1571   * @return void
     1572   */
     1573  function ClearCustomHeaders() {
     1574    $this->CustomHeader = array();
     1575  }
    13821576
    1383     /////////////////////////////////////////////////
    1384     // MISCELLANEOUS METHODS
    1385     /////////////////////////////////////////////////
     1577  /////////////////////////////////////////////////
     1578  // CLASS METHODS, MISCELLANEOUS
     1579  /////////////////////////////////////////////////
    13861580
    1387     /**
    1388      * Adds the error message to the error container.
    1389      * Returns void.
    1390      * @access private
    1391      * @return void
    1392      */
    1393     function SetError($msg) {
    1394         $this->error_count++;
    1395         $this->ErrorInfo = $msg;
     1581  /**
     1582   * Adds the error message to the error container.
     1583   * Returns void.
     1584   * @access private
     1585   * @return void
     1586   */
     1587  function SetError($msg) {
     1588    $this->error_count++;
     1589    $this->ErrorInfo = $msg;
     1590  }
     1591
     1592  /**
     1593   * Returns the proper RFC 822 formatted date.
     1594   * @access private
     1595   * @return string
     1596   */
     1597  function RFCDate() {
     1598    $tz = date('Z');
     1599    $tzs = ($tz < 0) ? '-' : '+';
     1600    $tz = abs($tz);
     1601    $tz = (int)($tz/3600)*100 + ($tz%3600)/60;
     1602    $result = sprintf("%s %s%04d", date('D, j M Y H:i:s'), $tzs, $tz);
     1603
     1604    return $result;
     1605  }
     1606
     1607  /**
     1608   * Returns the appropriate server variable.  Should work with both
     1609   * PHP 4.1.0+ as well as older versions.  Returns an empty string
     1610   * if nothing is found.
     1611   * @access private
     1612   * @return mixed
     1613   */
     1614  function ServerVar($varName) {
     1615    global $HTTP_SERVER_VARS;
     1616    global $HTTP_ENV_VARS;
     1617
     1618    if(!isset($_SERVER)) {
     1619      $_SERVER = $HTTP_SERVER_VARS;
     1620      if(!isset($_SERVER['REMOTE_ADDR'])) {
     1621        $_SERVER = $HTTP_ENV_VARS; // must be Apache
     1622      }
    13961623    }
    13971624
    1398     /**
    1399      * Returns the proper RFC 822 formatted date.
    1400      * @access private
    1401      * @return string
    1402      */
    1403     function RFCDate() {
    1404         $tz = date("Z");
    1405         $tzs = ($tz < 0) ? "-" : "+";
    1406         $tz = abs($tz);
    1407         $tz = ($tz/3600)*100 + ($tz%3600)/60;
    1408         $result = sprintf("%s %s%04d", date("D, j M Y H:i:s"), $tzs, $tz);
     1625    if(isset($_SERVER[$varName])) {
     1626      return $_SERVER[$varName];
     1627    } else {
     1628      return '';
     1629    }
     1630  }
    14091631
    1410         return $result;
     1632  /**
     1633   * Returns the server hostname or 'localhost.localdomain' if unknown.
     1634   * @access private
     1635   * @return string
     1636   */
     1637  function ServerHostname() {
     1638    if ($this->Hostname != '') {
     1639      $result = $this->Hostname;
     1640    } elseif ($this->ServerVar('SERVER_NAME') != '') {
     1641      $result = $this->ServerVar('SERVER_NAME');
     1642    } else {
     1643      $result = 'localhost.localdomain';
    14111644    }
    14121645
    1413     /**
    1414      * Returns the appropriate server variable.  Should work with both
    1415      * PHP 4.1.0+ as well as older versions.  Returns an empty string
    1416      * if nothing is found.
    1417      * @access private
    1418      * @return mixed
    1419      */
    1420     function ServerVar($varName) {
    1421         global $HTTP_SERVER_VARS;
    1422         global $HTTP_ENV_VARS;
     1646    return $result;
     1647  }
    14231648
    1424         if(!isset($_SERVER))
    1425         {
    1426             $_SERVER = $HTTP_SERVER_VARS;
    1427             if(!isset($_SERVER["REMOTE_ADDR"]))
    1428                 $_SERVER = $HTTP_ENV_VARS; // must be Apache
    1429         }
     1649  /**
     1650   * Returns a message in the appropriate language.
     1651   * @access private
     1652   * @return string
     1653   */
     1654  function Lang($key) {
     1655    if(count($this->language) < 1) {
     1656      $this->SetLanguage('en'); // set the default language
     1657    }
    14301658
    1431         if(isset($_SERVER[$varName]))
    1432             return $_SERVER[$varName];
    1433         else
    1434             return "";
     1659    if(isset($this->language[$key])) {
     1660      return $this->language[$key];
     1661    } else {
     1662      return 'Language string failed to load: ' . $key;
    14351663    }
     1664  }
    14361665
    1437     /**
    1438      * Returns the server hostname or 'localhost.localdomain' if unknown.
    1439      * @access private
    1440      * @return string
    1441      */
    1442     function ServerHostname() {
    1443         if ($this->Hostname != "")
    1444             $result = $this->Hostname;
    1445         elseif ($this->ServerVar('SERVER_NAME') != "")
    1446             $result = $this->ServerVar('SERVER_NAME');
    1447         else
    1448             $result = "localhost.localdomain";
     1666  /**
     1667   * Returns true if an error occurred.
     1668   * @return bool
     1669   */
     1670  function IsError() {
     1671    return ($this->error_count > 0);
     1672  }
    14491673
    1450         return $result;
    1451     }
     1674  /**
     1675   * Changes every end of line from CR or LF to CRLF.
     1676   * @access private
     1677   * @return string
     1678   */
     1679  function FixEOL($str) {
     1680    $str = str_replace("\r\n", "\n", $str);
     1681    $str = str_replace("\r", "\n", $str);
     1682    $str = str_replace("\n", $this->LE, $str);
     1683    return $str;
     1684  }
    14521685
    1453     /**
    1454      * Returns a message in the appropriate language.
    1455      * @access private
    1456      * @return string
    1457      */
    1458     function Lang($key) {
    1459         if(count($this->language) < 1)
    1460             $this->SetLanguage("en"); // set the default language
     1686  /**
     1687   * Adds a custom header.
     1688   * @return void
     1689   */
     1690  function AddCustomHeader($custom_header) {
     1691    $this->CustomHeader[] = explode(':', $custom_header, 2);
     1692  }
    14611693
    1462         if(isset($this->language[$key]))
    1463             return $this->language[$key];
    1464         else
    1465             return "Language string failed to load: " . $key;
     1694  /**
     1695   * Evaluates the message and returns modifications for inline images and backgrounds
     1696   * @access public
     1697   * @return $message
     1698   */
     1699  function MsgHTML($message,$basedir='') {
     1700    preg_match_all("/(src|background)=\"(.*)\"/Ui", $message, $images);
     1701    if(isset($images[2])) {
     1702      foreach($images[2] as $i => $url) {
     1703        // do not change urls for absolute images (thanks to corvuscorax)
     1704        if (!preg_match('/^[A-z][A-z]*:\/\//',$url)) {
     1705          $filename = basename($url);
     1706          $directory = dirname($url);
     1707          ($directory == '.')?$directory='':'';
     1708          $cid = 'cid:' . md5($filename);
     1709          $fileParts = split("\.", $filename);
     1710          $ext = $fileParts[1];
     1711          $mimeType = $this->_mime_types($ext);
     1712          if ( strlen($basedir) > 1 && substr($basedir,-1) != '/') { $basedir .= '/'; }
     1713          if ( strlen($directory) > 1 && substr($basedir,-1) != '/') { $directory .= '/'; }
     1714          $this->AddEmbeddedImage($basedir.$directory.$filename, md5($filename), $filename, 'base64', $mimeType);
     1715          if ( $this->AddEmbeddedImage($basedir.$directory.$filename, md5($filename), $filename, 'base64',$mimeType) ) {
     1716            $message = preg_replace("/".$images[1][$i]."=\"".preg_quote($url, '/')."\"/Ui", $images[1][$i]."=\"".$cid."\"", $message);
     1717          }
     1718        }
     1719      }
    14661720    }
     1721    $this->IsHTML(true);
     1722    $this->Body = $message;
     1723    $textMsg = trim(strip_tags(preg_replace('/<(head|title|style|script)[^>]*>.*?<\/\\1>/s','',$message)));
     1724    if ( !empty($textMsg) && empty($this->AltBody) ) {
     1725      $this->AltBody = $textMsg;
     1726    }
     1727    if ( empty($this->AltBody) ) {
     1728      $this->AltBody = 'To view this email message, open the email in with HTML compatibility!' . "\n\n";
     1729    }
     1730  }
    14671731
    1468     /**
    1469      * Returns true if an error occurred.
    1470      * @return bool
    1471      */
    1472     function IsError() {
    1473         return ($this->error_count > 0);
     1732  /**
     1733   * Gets the mime type of the embedded or inline image
     1734   * @access private
     1735   * @return mime type of ext
     1736   */
     1737  function _mime_types($ext = '') {
     1738    $mimes = array(
     1739      'hqx'  =>  'application/mac-binhex40',
     1740      'cpt'   =>  'application/mac-compactpro',
     1741      'doc'   =>  'application/msword',
     1742      'bin'   =>  'application/macbinary',
     1743      'dms'   =>  'application/octet-stream',
     1744      'lha'   =>  'application/octet-stream',
     1745      'lzh'   =>  'application/octet-stream',
     1746      'exe'   =>  'application/octet-stream',
     1747      'class' =>  'application/octet-stream',
     1748      'psd'   =>  'application/octet-stream',
     1749      'so'    =>  'application/octet-stream',
     1750      'sea'   =>  'application/octet-stream',
     1751      'dll'   =>  'application/octet-stream',
     1752      'oda'   =>  'application/oda',
     1753      'pdf'   =>  'application/pdf',
     1754      'ai'    =>  'application/postscript',
     1755      'eps'   =>  'application/postscript',
     1756      'ps'    =>  'application/postscript',
     1757      'smi'   =>  'application/smil',
     1758      'smil'  =>  'application/smil',
     1759      'mif'   =>  'application/vnd.mif',
     1760      'xls'   =>  'application/vnd.ms-excel',
     1761      'ppt'   =>  'application/vnd.ms-powerpoint',
     1762      'wbxml' =>  'application/vnd.wap.wbxml',
     1763      'wmlc'  =>  'application/vnd.wap.wmlc',
     1764      'dcr'   =>  'application/x-director',
     1765      'dir'   =>  'application/x-director',
     1766      'dxr'   =>  'application/x-director',
     1767      'dvi'   =>  'application/x-dvi',
     1768      'gtar'  =>  'application/x-gtar',
     1769      'php'   =>  'application/x-httpd-php',
     1770      'php4'  =>  'application/x-httpd-php',
     1771      'php3'  =>  'application/x-httpd-php',
     1772      'phtml' =>  'application/x-httpd-php',
     1773      'phps'  =>  'application/x-httpd-php-source',
     1774      'js'    =>  'application/x-javascript',
     1775      'swf'   =>  'application/x-shockwave-flash',
     1776      'sit'   =>  'application/x-stuffit',
     1777      'tar'   =>  'application/x-tar',
     1778      'tgz'   =>  'application/x-tar',
     1779      'xhtml' =>  'application/xhtml+xml',
     1780      'xht'   =>  'application/xhtml+xml',
     1781      'zip'   =>  'application/zip',
     1782      'mid'   =>  'audio/midi',
     1783      'midi'  =>  'audio/midi',
     1784      'mpga'  =>  'audio/mpeg',
     1785      'mp2'   =>  'audio/mpeg',
     1786      'mp3'   =>  'audio/mpeg',
     1787      'aif'   =>  'audio/x-aiff',
     1788      'aiff'  =>  'audio/x-aiff',
     1789      'aifc'  =>  'audio/x-aiff',
     1790      'ram'   =>  'audio/x-pn-realaudio',
     1791      'rm'    =>  'audio/x-pn-realaudio',
     1792      'rpm'   =>  'audio/x-pn-realaudio-plugin',
     1793      'ra'    =>  'audio/x-realaudio',
     1794      'rv'    =>  'video/vnd.rn-realvideo',
     1795      'wav'   =>  'audio/x-wav',
     1796      'bmp'   =>  'image/bmp',
     1797      'gif'   =>  'image/gif',
     1798      'jpeg'  =>  'image/jpeg',
     1799      'jpg'   =>  'image/jpeg',
     1800      'jpe'   =>  'image/jpeg',
     1801      'png'   =>  'image/png',
     1802      'tiff'  =>  'image/tiff',
     1803      'tif'   =>  'image/tiff',
     1804      'css'   =>  'text/css',
     1805      'html'  =>  'text/html',
     1806      'htm'   =>  'text/html',
     1807      'shtml' =>  'text/html',
     1808      'txt'   =>  'text/plain',
     1809      'text'  =>  'text/plain',
     1810      'log'   =>  'text/plain',
     1811      'rtx'   =>  'text/richtext',
     1812      'rtf'   =>  'text/rtf',
     1813      'xml'   =>  'text/xml',
     1814      'xsl'   =>  'text/xml',
     1815      'mpeg'  =>  'video/mpeg',
     1816      'mpg'   =>  'video/mpeg',
     1817      'mpe'   =>  'video/mpeg',
     1818      'qt'    =>  'video/quicktime',
     1819      'mov'   =>  'video/quicktime',
     1820      'avi'   =>  'video/x-msvideo',
     1821      'movie' =>  'video/x-sgi-movie',
     1822      'doc'   =>  'application/msword',
     1823      'word'  =>  'application/msword',
     1824      'xl'    =>  'application/excel',
     1825      'eml'   =>  'message/rfc822'
     1826    );
     1827    return ( ! isset($mimes[strtolower($ext)])) ? 'application/octet-stream' : $mimes[strtolower($ext)];
     1828  }
     1829
     1830  /**
     1831   * Set (or reset) Class Objects (variables)
     1832   *
     1833   * Usage Example:
     1834   * $page->set('X-Priority', '3');
     1835   *
     1836   * @access public
     1837   * @param string $name Parameter Name
     1838   * @param mixed $value Parameter Value
     1839   * NOTE: will not work with arrays, there are no arrays to set/reset
     1840   */
     1841  function set ( $name, $value = '' ) {
     1842    if ( isset($this->$name) ) {
     1843      $this->$name = $value;
     1844    } else {
     1845      $this->SetError('Cannot set or reset variable ' . $name);
     1846      return false;
    14741847    }
     1848  }
    14751849
    1476     /**
    1477      * Changes every end of line from CR or LF to CRLF.
    1478      * @access private
    1479      * @return string
    1480      */
    1481     function FixEOL($str) {
    1482         $str = str_replace("\r\n", "\n", $str);
    1483         $str = str_replace("\r", "\n", $str);
    1484         $str = str_replace("\n", $this->LE, $str);
    1485         return $str;
     1850  /**
     1851   * Read a file from a supplied filename and return it.
     1852   *
     1853   * @access public
     1854   * @param string $filename Parameter File Name
     1855   */
     1856  function getFile($filename) {
     1857    $return = '';
     1858    if ($fp = fopen($filename, 'rb')) {
     1859      while (!feof($fp)) {
     1860        $return .= fread($fp, 1024);
     1861      }
     1862      fclose($fp);
     1863      return $return;
     1864    } else {
     1865      return false;
    14861866    }
     1867  }
    14871868
    1488     /**
    1489      * Adds a custom header.
    1490      * @return void
    1491      */
    1492     function AddCustomHeader($custom_header) {
    1493         $this->CustomHeader[] = explode(":", $custom_header, 2);
    1494     }
     1869  /**
     1870   * Strips newlines to prevent header injection.
     1871   * @access private
     1872   * @param string $str String
     1873   * @return string
     1874   */
     1875  function SecureHeader($str) {
     1876    $str = trim($str);
     1877    $str = str_replace("\r", "", $str);
     1878    $str = str_replace("\n", "", $str);
     1879    return $str;
     1880  }
     1881
     1882  /**
     1883   * Set the private key file and password to sign the message.
     1884   *
     1885   * @access public
     1886   * @param string $key_filename Parameter File Name
     1887   * @param string $key_pass Password for private key
     1888   */
     1889  function Sign($key_filename, $key_pass) {
     1890    $this->sign_key_file = $key_filename;
     1891    $this->sign_key_pass = $key_pass;
     1892  }
     1893
    14951894}
    14961895
    14971896?>
  • wp-includes/class-smtp.php

     
    11<?php
    2 /**
    3  * SMTP - PHP SMTP class
    4  *
    5  * Define an SMTP class that can be used to connect and communicate with any
    6  * SMTP server. It implements all the SMTP functions defined in RFC821 except
    7  * TURN.
    8  *
    9  * @version 1.02
    10  * @author Chris Ryan
    11  * @license LGPL
    12  * @package PHPMailer
    13  */
     2/*~ class.smtp.php
     3.---------------------------------------------------------------------------.
     4|  Software: PHPMailer - PHP email class                                    |
     5|   Version: 2.0.2                                                          |
     6|   Contact: via sourceforge.net support pages (also www.codeworxtech.com)  |
     7|      Info: http://phpmailer.sourceforge.net                               |
     8|   Support: http://sourceforge.net/projects/phpmailer/                     |
     9| ------------------------------------------------------------------------- |
     10|    Author: Andy Prevost (project admininistrator)                         |
     11|    Author: Brent R. Matzelle (original founder)                           |
     12| Copyright (c) 2004-2007, Andy Prevost. All Rights Reserved.               |
     13| Copyright (c) 2001-2003, Brent R. Matzelle                                |
     14| ------------------------------------------------------------------------- |
     15|   License: Distributed under the Lesser General Public License (LGPL)     |
     16|            http://www.gnu.org/copyleft/lesser.html                        |
     17| This program is distributed in the hope that it will be useful - WITHOUT  |
     18| ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or     |
     19| FITNESS FOR A PARTICULAR PURPOSE.                                         |
     20| ------------------------------------------------------------------------- |
     21| We offer a number of paid services (www.codeworxtech.com):                |
     22| - Web Hosting on highly optimized fast and secure servers                 |
     23| - Technology Consulting                                                   |
     24| - Oursourcing (highly qualified programmers and graphic designers)        |
     25'---------------------------------------------------------------------------'
    1426
    1527/**
    1628 * SMTP is rfc 821 compliant and implements all the rfc 821 SMTP
    1729 * commands except TURN which will always return a not implemented
    1830 * error. SMTP also provides some utility methods for sending mail
    1931 * to an SMTP server.
    20  *
    2132 * @package PHPMailer
    2233 * @author Chris Ryan
    2334 */
     35
    2436class SMTP
    2537{
    26     /**
    27      *  SMTP server port
    28      *  @var int
    29      */
    30     var $SMTP_PORT = 25;
     38  /**
     39   *  SMTP server port
     40   *  @var int
     41   */
     42  var $SMTP_PORT = 25;
    3143
    32     /**
    33      *  SMTP reply line ending
    34      *  @var string
    35      */
    36     var $CRLF = "\r\n";
     44  /**
     45   *  SMTP reply line ending
     46   *  @var string
     47   */
     48  var $CRLF = "\r\n";
    3749
    38     /**
    39      *  Sets whether debugging is turned on
    40      *  @var bool
    41      */
    42     var $do_debug;       # the level of debug to perform
     50  /**
     51   *  Sets whether debugging is turned on
     52   *  @var bool
     53   */
     54  var $do_debug;       # the level of debug to perform
    4355
    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     /**#@-*/
     56  /**
     57   *  Sets VERP use on/off (default is off)
     58   *  @var bool
     59   */
     60  var $do_verp = false;
    5161
    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;
     62  /**#@+
     63   * @access private
     64   */
     65  var $smtp_conn;      # the socket to the server
     66  var $error;          # error if any on the last call
     67  var $helo_rply;      # the reply the server sent to us for HELO
     68  /**#@-*/
    6169
    62         $this->do_debug = 0;
    63     }
     70  /**
     71   * Initialize the class so that the data is in a known state.
     72   * @access public
     73   * @return void
     74   */
     75  function SMTP() {
     76    $this->smtp_conn = 0;
     77    $this->error = null;
     78    $this->helo_rply = null;
    6479
    65     /*************************************************************
    66      *                    CONNECTION FUNCTIONS                  *
    67      ***********************************************************/
     80    $this->do_debug = 0;
     81  }
    6882
    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;
     83  /*************************************************************
     84   *                    CONNECTION FUNCTIONS                  *
     85   ***********************************************************/
    8586
    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         }
     87  /**
     88   * Connect to the server specified on the port specified.
     89   * If the port is not specified use the default SMTP_PORT.
     90   * If tval is specified then a connection will try and be
     91   * established with the server for that number of seconds.
     92   * If tval is not specified the default is 30 seconds to
     93   * try on the connection.
     94   *
     95   * SMTP CODE SUCCESS: 220
     96   * SMTP CODE FAILURE: 421
     97   * @access public
     98   * @return bool
     99   */
     100  function Connect($host,$port=0,$tval=30) {
     101    # set the error val to null so there is no confusion
     102    $this->error = null;
    95103
    96         if(empty($port)) {
    97             $port = $this->SMTP_PORT;
    98         }
     104    # make sure we are __not__ connected
     105    if($this->connected()) {
     106      # ok we are connected! what should we do?
     107      # for now we will just give an error saying we
     108      # are already connected
     109      $this->error = array("error" => "Already connected to a server");
     110      return false;
     111    }
    99112
    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         }
     113    if(empty($port)) {
     114      $port = $this->SMTP_PORT;
     115    }
    117116
    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);
     117    #connect to the smtp server
     118    $this->smtp_conn = fsockopen($host,    # the host of the server
     119                                 $port,    # the port to use
     120                                 $errno,   # error number if any
     121                                 $errstr,  # error message if any
     122                                 $tval);   # give up after ? secs
     123    # verify we connected properly
     124    if(empty($this->smtp_conn)) {
     125      $this->error = array("error" => "Failed to connect to server",
     126                           "errno" => $errno,
     127                           "errstr" => $errstr);
     128      if($this->do_debug >= 1) {
     129        echo "SMTP -> ERROR: " . $this->error["error"] .
     130                 ": $errstr ($errno)" . $this->CRLF;
     131      }
     132      return false;
     133    }
    123134
    124         # get any announcement stuff
    125         $announce = $this->get_lines();
     135    # sometimes the SMTP server takes a little longer to respond
     136    # so we will give it a longer timeout for the first read
     137    // Windows still does not have support for this timeout function
     138    if(substr(PHP_OS, 0, 3) != "WIN")
     139     socket_set_timeout($this->smtp_conn, $tval, 0);
    126140
    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);
     141    # get any announcement stuff
     142    $announce = $this->get_lines();
    130143
    131         if($this->do_debug >= 2) {
    132             echo "SMTP -> FROM SERVER:" . $this->CRLF . $announce;
    133         }
     144    # set the timeout  of any socket functions at 1/10 of a second
     145    //if(function_exists("socket_set_timeout"))
     146    //   socket_set_timeout($this->smtp_conn, 0, 100000);
    134147
    135         return true;
     148    if($this->do_debug >= 2) {
     149      echo "SMTP -> FROM SERVER:" . $this->CRLF . $announce;
    136150    }
    137151
    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);
     152    return true;
     153  }
    147154
    148         $rply = $this->get_lines();
    149         $code = substr($rply,0,3);
     155  /**
     156   * Performs SMTP authentication.  Must be run after running the
     157   * Hello() method.  Returns true if successfully authenticated.
     158   * @access public
     159   * @return bool
     160   */
     161  function Authenticate($username, $password) {
     162    // Start authentication
     163    fputs($this->smtp_conn,"AUTH LOGIN" . $this->CRLF);
    150164
    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         }
     165    $rply = $this->get_lines();
     166    $code = substr($rply,0,3);
    162167
    163         // Send encoded username
    164         fputs($this->smtp_conn, base64_encode($username) . $this->CRLF);
     168    if($code != 334) {
     169      $this->error =
     170        array("error" => "AUTH not accepted from server",
     171              "smtp_code" => $code,
     172              "smtp_msg" => substr($rply,4));
     173      if($this->do_debug >= 1) {
     174        echo "SMTP -> ERROR: " . $this->error["error"] .
     175                 ": " . $rply . $this->CRLF;
     176      }
     177      return false;
     178    }
    165179
    166         $rply = $this->get_lines();
    167         $code = substr($rply,0,3);
     180    // Send encoded username
     181    fputs($this->smtp_conn, base64_encode($username) . $this->CRLF);
    168182
    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         }
     183    $rply = $this->get_lines();
     184    $code = substr($rply,0,3);
    180185
    181         // Send encoded password
    182         fputs($this->smtp_conn, base64_encode($password) . $this->CRLF);
     186    if($code != 334) {
     187      $this->error =
     188        array("error" => "Username not accepted from server",
     189              "smtp_code" => $code,
     190              "smtp_msg" => substr($rply,4));
     191      if($this->do_debug >= 1) {
     192        echo "SMTP -> ERROR: " . $this->error["error"] .
     193                 ": " . $rply . $this->CRLF;
     194      }
     195      return false;
     196    }
    183197
    184         $rply = $this->get_lines();
    185         $code = substr($rply,0,3);
     198    // Send encoded password
     199    fputs($this->smtp_conn, base64_encode($password) . $this->CRLF);
    186200
    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         }
     201    $rply = $this->get_lines();
     202    $code = substr($rply,0,3);
    198203
    199         return true;
     204    if($code != 235) {
     205      $this->error =
     206        array("error" => "Password not accepted from server",
     207              "smtp_code" => $code,
     208              "smtp_msg" => substr($rply,4));
     209      if($this->do_debug >= 1) {
     210        echo "SMTP -> ERROR: " . $this->error["error"] .
     211                 ": " . $rply . $this->CRLF;
     212      }
     213      return false;
    200214    }
    201215
    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
     216    return true;
     217  }
     218
     219  /**
     220   * Returns true if connected to a server otherwise false
     221   * @access private
     222   * @return bool
     223   */
     224  function Connected() {
     225    if(!empty($this->smtp_conn)) {
     226      $sock_status = socket_get_status($this->smtp_conn);
     227      if($sock_status["eof"]) {
     228        # hmm this is an odd situation... the socket is
     229        # valid but we are not connected anymore
     230        if($this->do_debug >= 1) {
     231            echo "SMTP -> NOTICE:" . $this->CRLF .
     232                 "EOF caught while checking if connected";
    221233        }
     234        $this->Close();
    222235        return false;
     236      }
     237      return true; # everything looks good
    223238    }
     239    return false;
     240  }
    224241
    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         }
     242  /**
     243   * Closes the socket and cleans up the state of the class.
     244   * It is not considered good to use this function without
     245   * first trying to use QUIT.
     246   * @access public
     247   * @return void
     248   */
     249  function Close() {
     250    $this->error = null; # so there is no confusion
     251    $this->helo_rply = null;
     252    if(!empty($this->smtp_conn)) {
     253      # close the connection and cleanup
     254      fclose($this->smtp_conn);
     255      $this->smtp_conn = 0;
    240256    }
     257  }
    241258
     259  /***************************************************************
     260   *                        SMTP COMMANDS                       *
     261   *************************************************************/
    242262
    243     /***************************************************************
    244      *                        SMTP COMMANDS                       *
    245      *************************************************************/
     263  /**
     264   * Issues a data command and sends the msg_data to the server
     265   * finializing the mail transaction. $msg_data is the message
     266   * that is to be send with the headers. Each header needs to be
     267   * on a single line followed by a <CRLF> with the message headers
     268   * and the message body being seperated by and additional <CRLF>.
     269   *
     270   * Implements rfc 821: DATA <CRLF>
     271   *
     272   * SMTP CODE INTERMEDIATE: 354
     273   *     [data]
     274   *     <CRLF>.<CRLF>
     275   *     SMTP CODE SUCCESS: 250
     276   *     SMTP CODE FAILURE: 552,554,451,452
     277   * SMTP CODE FAILURE: 451,554
     278   * SMTP CODE ERROR  : 500,501,503,421
     279   * @access public
     280   * @return bool
     281   */
     282  function Data($msg_data) {
     283    $this->error = null; # so no confusion is caused
    246284
    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 separated 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
     285    if(!$this->connected()) {
     286      $this->error = array(
     287              "error" => "Called Data() without being connected");
     288      return false;
     289    }
    268290
    269         if(!$this->connected()) {
    270             $this->error = array(
    271                     "error" => "Called Data() without being connected");
    272             return false;
    273         }
     291    fputs($this->smtp_conn,"DATA" . $this->CRLF);
    274292
    275         fputs($this->smtp_conn,"DATA" . $this->CRLF);
     293    $rply = $this->get_lines();
     294    $code = substr($rply,0,3);
    276295
    277         $rply = $this->get_lines();
    278         $code = substr($rply,0,3);
     296    if($this->do_debug >= 2) {
     297      echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
     298    }
    279299
    280         if($this->do_debug >= 2) {
    281             echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
    282         }
     300    if($code != 354) {
     301      $this->error =
     302        array("error" => "DATA command not accepted from server",
     303              "smtp_code" => $code,
     304              "smtp_msg" => substr($rply,4));
     305      if($this->do_debug >= 1) {
     306        echo "SMTP -> ERROR: " . $this->error["error"] .
     307                 ": " . $rply . $this->CRLF;
     308      }
     309      return false;
     310    }
    283311
    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         }
     312    # the server is ready to accept data!
     313    # according to rfc 821 we should not send more than 1000
     314    # including the CRLF
     315    # characters on a single line so we will break the data up
     316    # into lines by \r and/or \n then if needed we will break
     317    # each of those into smaller lines to fit within the limit.
     318    # in addition we will be looking for lines that start with
     319    # a period '.' and append and additional period '.' to that
     320    # line. NOTE: this does not count towards are limit.
    295321
    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.
     322    # normalize the line breaks so we know the explode works
     323    $msg_data = str_replace("\r\n","\n",$msg_data);
     324    $msg_data = str_replace("\r","\n",$msg_data);
     325    $lines = explode("\n",$msg_data);
    305326
    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);
     327    # we need to find a good way to determine is headers are
     328    # in the msg_data or if it is a straight msg body
     329    # currently I am assuming rfc 822 definitions of msg headers
     330    # and if the first field of the first line (':' sperated)
     331    # does not contain a space then it _should_ be a header
     332    # and we can process all lines before a blank "" line as
     333    # headers.
     334    $field = substr($lines[0],0,strpos($lines[0],":"));
     335    $in_headers = false;
     336    if(!empty($field) && !strstr($field," ")) {
     337      $in_headers = true;
     338    }
    310339
    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],":"));
     340    $max_line_length = 998; # used below; set here for ease in change
     341
     342    while(list(,$line) = @each($lines)) {
     343      $lines_out = null;
     344      if($line == "" && $in_headers) {
    319345        $in_headers = false;
    320         if(!empty($field) && !strstr($field," ")) {
    321             $in_headers = true;
    322         }
     346      }
     347      # ok we need to break this line up into several
     348      # smaller lines
     349      while(strlen($line) > $max_line_length) {
     350        $pos = strrpos(substr($line,0,$max_line_length)," ");
    323351
    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             }
     352        # Patch to fix DOS attack
     353        if(!$pos) {
     354          $pos = $max_line_length - 1;
    362355        }
    363356
    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;
     357        $lines_out[] = substr($line,0,$pos);
     358        $line = substr($line,$pos + 1);
     359        # if we are processing headers we need to
     360        # add a LWSP-char to the front of the new line
     361        # rfc 822 on long msg headers
     362        if($in_headers) {
     363          $line = "\t" . $line;
    373364        }
     365      }
     366      $lines_out[] = $line;
    374367
    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;
     368      # now send the lines to the server
     369      while(list(,$line_out) = @each($lines_out)) {
     370        if(strlen($line_out) > 0)
     371        {
     372          if(substr($line_out, 0, 1) == ".") {
     373            $line_out = "." . $line_out;
     374          }
    385375        }
    386         return true;
     376        fputs($this->smtp_conn,$line_out . $this->CRLF);
     377      }
    387378    }
    388379
    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
     380    # ok all the message data has been sent so lets get this
     381    # over with aleady
     382    fputs($this->smtp_conn, $this->CRLF . "." . $this->CRLF);
    407383
    408         if(!$this->connected()) {
    409             $this->error = array(
    410                     "error" => "Called Expand() without being connected");
    411             return false;
    412         }
     384    $rply = $this->get_lines();
     385    $code = substr($rply,0,3);
    413386
    414         fputs($this->smtp_conn,"EXPN " . $name . $this->CRLF);
     387    if($this->do_debug >= 2) {
     388      echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
     389    }
    415390
    416         $rply = $this->get_lines();
    417         $code = substr($rply,0,3);
     391    if($code != 250) {
     392      $this->error =
     393        array("error" => "DATA not accepted from server",
     394              "smtp_code" => $code,
     395              "smtp_msg" => substr($rply,4));
     396      if($this->do_debug >= 1) {
     397        echo "SMTP -> ERROR: " . $this->error["error"] .
     398                 ": " . $rply . $this->CRLF;
     399      }
     400      return false;
     401    }
     402    return true;
     403  }
    418404
    419         if($this->do_debug >= 2) {
    420             echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
    421         }
     405  /**
     406   * Expand takes the name and asks the server to list all the
     407   * people who are members of the _list_. Expand will return
     408   * back and array of the result or false if an error occurs.
     409   * Each value in the array returned has the format of:
     410   *     [ <full-name> <sp> ] <path>
     411   * The definition of <path> is defined in rfc 821
     412   *
     413   * Implements rfc 821: EXPN <SP> <string> <CRLF>
     414   *
     415   * SMTP CODE SUCCESS: 250
     416   * SMTP CODE FAILURE: 550
     417   * SMTP CODE ERROR  : 500,501,502,504,421
     418   * @access public
     419   * @return string array
     420   */
     421  function Expand($name) {
     422    $this->error = null; # so no confusion is caused
    422423
    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         }
     424    if(!$this->connected()) {
     425      $this->error = array(
     426            "error" => "Called Expand() without being connected");
     427      return false;
     428    }
    434429
    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         }
     430    fputs($this->smtp_conn,"EXPN " . $name . $this->CRLF);
    440431
    441         return $list;
     432    $rply = $this->get_lines();
     433    $code = substr($rply,0,3);
     434
     435    if($this->do_debug >= 2) {
     436      echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
    442437    }
    443438
    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
     439    if($code != 250) {
     440      $this->error =
     441        array("error" => "EXPN not accepted from server",
     442              "smtp_code" => $code,
     443              "smtp_msg" => substr($rply,4));
     444      if($this->do_debug >= 1) {
     445        echo "SMTP -> ERROR: " . $this->error["error"] .
     446                 ": " . $rply . $this->CRLF;
     447      }
     448      return false;
     449    }
    458450
    459         if(!$this->connected()) {
    460             $this->error = array(
    461                     "error" => "Called Hello() without being connected");
    462             return false;
    463         }
     451    # parse the reply and place in our array to return to user
     452    $entries = explode($this->CRLF,$rply);
     453    while(list(,$l) = @each($entries)) {
     454      $list[] = substr($l,4);
     455    }
    464456
    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         }
     457    return $list;
     458  }
    472459
    473         // Send extended hello first (RFC 2821)
    474         if(!$this->SendHello("EHLO", $host))
    475         {
    476             if(!$this->SendHello("HELO", $host))
    477                 return false;
    478         }
     460  /**
     461   * Sends the HELO command to the smtp server.
     462   * This makes sure that we and the server are in
     463   * the same known state.
     464   *
     465   * Implements from rfc 821: HELO <SP> <domain> <CRLF>
     466   *
     467   * SMTP CODE SUCCESS: 250
     468   * SMTP CODE ERROR  : 500, 501, 504, 421
     469   * @access public
     470   * @return bool
     471   */
     472  function Hello($host="") {
     473    $this->error = null; # so no confusion is caused
    479474
    480         return true;
     475    if(!$this->connected()) {
     476      $this->error = array(
     477            "error" => "Called Hello() without being connected");
     478      return false;
    481479    }
    482480
    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);
     481    # if a hostname for the HELO was not specified determine
     482    # a suitable one to send
     483    if(empty($host)) {
     484      # we need to determine some sort of appopiate default
     485      # to send to the server
     486      $host = "localhost";
     487    }
    490488
    491         $rply = $this->get_lines();
    492         $code = substr($rply,0,3);
     489    // Send extended hello first (RFC 2821)
     490    if(!$this->SendHello("EHLO", $host))
     491    {
     492      if(!$this->SendHello("HELO", $host))
     493          return false;
     494    }
    493495
    494         if($this->do_debug >= 2) {
    495             echo "SMTP -> FROM SERVER: " . $this->CRLF . $rply;
    496         }
     496    return true;
     497  }
    497498
    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         }
     499  /**
     500   * Sends a HELO/EHLO command.
     501   * @access private
     502   * @return bool
     503   */
     504  function SendHello($hello, $host) {
     505    fputs($this->smtp_conn, $hello . " " . $host . $this->CRLF);
    509506
    510         $this->helo_rply = $rply;
     507    $rply = $this->get_lines();
     508    $code = substr($rply,0,3);
    511509
    512         return true;
     510    if($this->do_debug >= 2) {
     511      echo "SMTP -> FROM SERVER: " . $this->CRLF . $rply;
    513512    }
    514513
    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
     514    if($code != 250) {
     515      $this->error =
     516        array("error" => $hello . " not accepted from server",
     517              "smtp_code" => $code,
     518              "smtp_msg" => substr($rply,4));
     519      if($this->do_debug >= 1) {
     520        echo "SMTP -> ERROR: " . $this->error["error"] .
     521                 ": " . $rply . $this->CRLF;
     522      }
     523      return false;
     524    }
    532525
    533         if(!$this->connected()) {
    534             $this->error = array(
    535                     "error" => "Called Help() without being connected");
    536             return false;
    537         }
     526    $this->helo_rply = $rply;
    538527
    539         $extra = "";
    540         if(!empty($keyword)) {
    541             $extra = " " . $keyword;
    542         }
     528    return true;
     529  }
    543530
    544         fputs($this->smtp_conn,"HELP" . $extra . $this->CRLF);
     531  /**
     532   * Gets help information on the keyword specified. If the keyword
     533   * is not specified then returns generic help, ussually contianing
     534   * A list of keywords that help is available on. This function
     535   * returns the results back to the user. It is up to the user to
     536   * handle the returned data. If an error occurs then false is
     537   * returned with $this->error set appropiately.
     538   *
     539   * Implements rfc 821: HELP [ <SP> <string> ] <CRLF>
     540   *
     541   * SMTP CODE SUCCESS: 211,214
     542   * SMTP CODE ERROR  : 500,501,502,504,421
     543   * @access public
     544   * @return string
     545   */
     546  function Help($keyword="") {
     547    $this->error = null; # to avoid confusion
    545548
    546         $rply = $this->get_lines();
    547         $code = substr($rply,0,3);
     549    if(!$this->connected()) {
     550      $this->error = array(
     551              "error" => "Called Help() without being connected");
     552      return false;
     553    }
    548554
    549         if($this->do_debug >= 2) {
    550             echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
    551         }
     555    $extra = "";
     556    if(!empty($keyword)) {
     557      $extra = " " . $keyword;
     558    }
    552559
    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         }
     560    fputs($this->smtp_conn,"HELP" . $extra . $this->CRLF);
    564561
    565         return $rply;
     562    $rply = $this->get_lines();
     563    $code = substr($rply,0,3);
     564
     565    if($this->do_debug >= 2) {
     566      echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
    566567    }
    567568
    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
     569    if($code != 211 && $code != 214) {
     570      $this->error =
     571        array("error" => "HELP not accepted from server",
     572              "smtp_code" => $code,
     573              "smtp_msg" => substr($rply,4));
     574      if($this->do_debug >= 1) {
     575        echo "SMTP -> ERROR: " . $this->error["error"] .
     576                 ": " . $rply . $this->CRLF;
     577      }
     578      return false;
     579    }
    584580
    585         if(!$this->connected()) {
    586             $this->error = array(
    587                     "error" => "Called Mail() without being connected");
    588             return false;
    589         }
     581    return $rply;
     582  }
    590583
    591         fputs($this->smtp_conn,"MAIL FROM:<" . $from . ">" . $this->CRLF);
     584  /**
     585   * Starts a mail transaction from the email address specified in
     586   * $from. Returns true if successful or false otherwise. If True
     587   * the mail transaction is started and then one or more Recipient
     588   * commands may be called followed by a Data command.
     589   *
     590   * Implements rfc 821: MAIL <SP> FROM:<reverse-path> <CRLF>
     591   *
     592   * SMTP CODE SUCCESS: 250
     593   * SMTP CODE SUCCESS: 552,451,452
     594   * SMTP CODE SUCCESS: 500,501,421
     595   * @access public
     596   * @return bool
     597   */
     598  function Mail($from) {
     599    $this->error = null; # so no confusion is caused
    592600
    593         $rply = $this->get_lines();
    594         $code = substr($rply,0,3);
     601    if(!$this->connected()) {
     602      $this->error = array(
     603              "error" => "Called Mail() without being connected");
     604      return false;
     605    }
    595606
    596         if($this->do_debug >= 2) {
    597             echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
    598         }
     607    $useVerp = ($this->do_verp ? "XVERP" : "");
     608    fputs($this->smtp_conn,"MAIL FROM:<" . $from . ">" . $useVerp . $this->CRLF);
    599609
    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;
     610    $rply = $this->get_lines();
     611    $code = substr($rply,0,3);
     612
     613    if($this->do_debug >= 2) {
     614      echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
    612615    }
    613616
    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
     617    if($code != 250) {
     618      $this->error =
     619        array("error" => "MAIL not accepted from server",
     620              "smtp_code" => $code,
     621              "smtp_msg" => substr($rply,4));
     622      if($this->do_debug >= 1) {
     623        echo "SMTP -> ERROR: " . $this->error["error"] .
     624                 ": " . $rply . $this->CRLF;
     625      }
     626      return false;
     627    }
     628    return true;
     629  }
    626630
    627         if(!$this->connected()) {
    628             $this->error = array(
    629                     "error" => "Called Noop() without being connected");
    630             return false;
    631         }
     631  /**
     632   * Sends the command NOOP to the SMTP server.
     633   *
     634   * Implements from rfc 821: NOOP <CRLF>
     635   *
     636   * SMTP CODE SUCCESS: 250
     637   * SMTP CODE ERROR  : 500, 421
     638   * @access public
     639   * @return bool
     640   */
     641  function Noop() {
     642    $this->error = null; # so no confusion is caused
    632643
    633         fputs($this->smtp_conn,"NOOP" . $this->CRLF);
     644    if(!$this->connected()) {
     645      $this->error = array(
     646              "error" => "Called Noop() without being connected");
     647      return false;
     648    }
    634649
    635         $rply = $this->get_lines();
    636         $code = substr($rply,0,3);
     650    fputs($this->smtp_conn,"NOOP" . $this->CRLF);
    637651
    638         if($this->do_debug >= 2) {
    639             echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
    640         }
     652    $rply = $this->get_lines();
     653    $code = substr($rply,0,3);
    641654
    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;
     655    if($this->do_debug >= 2) {
     656      echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
    654657    }
    655658
    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
     659    if($code != 250) {
     660      $this->error =
     661        array("error" => "NOOP not accepted from server",
     662              "smtp_code" => $code,
     663              "smtp_msg" => substr($rply,4));
     664      if($this->do_debug >= 1) {
     665        echo "SMTP -> ERROR: " . $this->error["error"] .
     666                 ": " . $rply . $this->CRLF;
     667      }
     668      return false;
     669    }
     670    return true;
     671  }
    669672
    670         if(!$this->connected()) {
    671             $this->error = array(
    672                     "error" => "Called Quit() without being connected");
    673             return false;
    674         }
     673  /**
     674   * Sends the quit command to the server and then closes the socket
     675   * if there is no error or the $close_on_error argument is true.
     676   *
     677   * Implements from rfc 821: QUIT <CRLF>
     678   *
     679   * SMTP CODE SUCCESS: 221
     680   * SMTP CODE ERROR  : 500
     681   * @access public
     682   * @return bool
     683   */
     684  function Quit($close_on_error=true) {
     685    $this->error = null; # so there is no confusion
    675686
    676         # send the quit command to the server
    677         fputs($this->smtp_conn,"quit" . $this->CRLF);
     687    if(!$this->connected()) {
     688      $this->error = array(
     689              "error" => "Called Quit() without being connected");
     690      return false;
     691    }
    678692
    679         # get any good-bye messages
    680         $byemsg = $this->get_lines();
     693    # send the quit command to the server
     694    fputs($this->smtp_conn,"quit" . $this->CRLF);
    681695
    682         if($this->do_debug >= 2) {
    683             echo "SMTP -> FROM SERVER:" . $this->CRLF . $byemsg;
    684         }
     696    # get any good-bye messages
     697    $byemsg = $this->get_lines();
    685698
    686         $rval = true;
    687         $e = null;
     699    if($this->do_debug >= 2) {
     700      echo "SMTP -> FROM SERVER:" . $this->CRLF . $byemsg;
     701    }
    688702
    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         }
     703    $rval = true;
     704    $e = null;
    701705
    702         if(empty($e) || $close_on_error) {
    703             $this->Close();
    704         }
     706    $code = substr($byemsg,0,3);
     707    if($code != 221) {
     708      # use e as a tmp var cause Close will overwrite $this->error
     709      $e = array("error" => "SMTP server rejected quit command",
     710                 "smtp_code" => $code,
     711                 "smtp_rply" => substr($byemsg,4));
     712      $rval = false;
     713      if($this->do_debug >= 1) {
     714        echo "SMTP -> ERROR: " . $e["error"] . ": " .
     715                 $byemsg . $this->CRLF;
     716      }
     717    }
    705718
    706         return $rval;
     719    if(empty($e) || $close_on_error) {
     720      $this->Close();
    707721    }
    708722
    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    return $rval;
     724  }
    723725
    724         if(!$this->connected()) {
    725             $this->error = array(
    726                     "error" => "Called Recipient() without being connected");
    727             return false;
    728         }
     726  /**
     727   * Sends the command RCPT to the SMTP server with the TO: argument of $to.
     728   * Returns true if the recipient was accepted false if it was rejected.
     729   *
     730   * Implements from rfc 821: RCPT <SP> TO:<forward-path> <CRLF>
     731   *
     732   * SMTP CODE SUCCESS: 250,251
     733   * SMTP CODE FAILURE: 550,551,552,553,450,451,452
     734   * SMTP CODE ERROR  : 500,501,503,421
     735   * @access public
     736   * @return bool
     737   */
     738  function Recipient($to) {
     739    $this->error = null; # so no confusion is caused
    729740
    730         fputs($this->smtp_conn,"RCPT TO:<" . $to . ">" . $this->CRLF);
     741    if(!$this->connected()) {
     742      $this->error = array(
     743              "error" => "Called Recipient() without being connected");
     744      return false;
     745    }
    731746
    732         $rply = $this->get_lines();
    733         $code = substr($rply,0,3);
     747    fputs($this->smtp_conn,"RCPT TO:<" . $to . ">" . $this->CRLF);
    734748
    735         if($this->do_debug >= 2) {
    736             echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
    737         }
     749    $rply = $this->get_lines();
     750    $code = substr($rply,0,3);
    738751
    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;
     752    if($this->do_debug >= 2) {
     753      echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
    751754    }
    752755
    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
     756    if($code != 250 && $code != 251) {
     757      $this->error =
     758        array("error" => "RCPT not accepted from server",
     759              "smtp_code" => $code,
     760              "smtp_msg" => substr($rply,4));
     761      if($this->do_debug >= 1) {
     762        echo "SMTP -> ERROR: " . $this->error["error"] .
     763                 ": " . $rply . $this->CRLF;
     764      }
     765      return false;
     766    }
     767    return true;
     768  }
    767769
    768         if(!$this->connected()) {
    769             $this->error = array(
    770                     "error" => "Called Reset() without being connected");
    771             return false;
    772         }
     770  /**
     771   * Sends the RSET command to abort and transaction that is
     772   * currently in progress. Returns true if successful false
     773   * otherwise.
     774   *
     775   * Implements rfc 821: RSET <CRLF>
     776   *
     777   * SMTP CODE SUCCESS: 250
     778   * SMTP CODE ERROR  : 500,501,504,421
     779   * @access public
     780   * @return bool
     781   */
     782  function Reset() {
     783    $this->error = null; # so no confusion is caused
    773784
    774         fputs($this->smtp_conn,"RSET" . $this->CRLF);
     785    if(!$this->connected()) {
     786      $this->error = array(
     787              "error" => "Called Reset() without being connected");
     788      return false;
     789    }
    775790
    776         $rply = $this->get_lines();
    777         $code = substr($rply,0,3);
     791    fputs($this->smtp_conn,"RSET" . $this->CRLF);
    778792
    779         if($this->do_debug >= 2) {
    780             echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
    781         }
     793    $rply = $this->get_lines();
     794    $code = substr($rply,0,3);
    782795
    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         }
     796    if($this->do_debug >= 2) {
     797      echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
     798    }
    794799
    795         return true;
     800    if($code != 250) {
     801      $this->error =
     802        array("error" => "RSET failed",
     803              "smtp_code" => $code,
     804              "smtp_msg" => substr($rply,4));
     805      if($this->do_debug >= 1) {
     806        echo "SMTP -> ERROR: " . $this->error["error"] .
     807                 ": " . $rply . $this->CRLF;
     808      }
     809      return false;
    796810    }
    797811
    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
     812    return true;
     813  }
    816814
    817         if(!$this->connected()) {
    818             $this->error = array(
    819                     "error" => "Called Send() without being connected");
    820             return false;
    821         }
     815  /**
     816   * Starts a mail transaction from the email address specified in
     817   * $from. Returns true if successful or false otherwise. If True
     818   * the mail transaction is started and then one or more Recipient
     819   * commands may be called followed by a Data command. This command
     820   * will send the message to the users terminal if they are logged
     821   * in.
     822   *
     823   * Implements rfc 821: SEND <SP> FROM:<reverse-path> <CRLF>
     824   *
     825   * SMTP CODE SUCCESS: 250
     826   * SMTP CODE SUCCESS: 552,451,452
     827   * SMTP CODE SUCCESS: 500,501,502,421
     828   * @access public
     829   * @return bool
     830   */
     831  function Send($from) {
     832    $this->error = null; # so no confusion is caused
    822833
    823         fputs($this->smtp_conn,"SEND FROM:" . $from . $this->CRLF);
     834    if(!$this->connected()) {
     835      $this->error = array(
     836              "error" => "Called Send() without being connected");
     837      return false;
     838    }
    824839
    825         $rply = $this->get_lines();
    826         $code = substr($rply,0,3);
     840    fputs($this->smtp_conn,"SEND FROM:" . $from . $this->CRLF);
    827841
    828         if($this->do_debug >= 2) {
    829             echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
    830         }
     842    $rply = $this->get_lines();
     843    $code = substr($rply,0,3);
    831844
    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;
     845    if($this->do_debug >= 2) {
     846      echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
    844847    }
    845848
    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
     849    if($code != 250) {
     850      $this->error =
     851        array("error" => "SEND not accepted from server",
     852              "smtp_code" => $code,
     853              "smtp_msg" => substr($rply,4));
     854      if($this->do_debug >= 1) {
     855        echo "SMTP -> ERROR: " . $this->error["error"] .
     856                 ": " . $rply . $this->CRLF;
     857      }
     858      return false;
     859    }
     860    return true;
     861  }
    864862
    865         if(!$this->connected()) {
    866             $this->error = array(
    867                 "error" => "Called SendAndMail() without being connected");
    868             return false;
    869         }
     863  /**
     864   * Starts a mail transaction from the email address specified in
     865   * $from. Returns true if successful or false otherwise. If True
     866   * the mail transaction is started and then one or more Recipient
     867   * commands may be called followed by a Data command. This command
     868   * will send the message to the users terminal if they are logged
     869   * in and send them an email.
     870   *
     871   * Implements rfc 821: SAML <SP> FROM:<reverse-path> <CRLF>
     872   *
     873   * SMTP CODE SUCCESS: 250
     874   * SMTP CODE SUCCESS: 552,451,452
     875   * SMTP CODE SUCCESS: 500,501,502,421
     876   * @access public
     877   * @return bool
     878   */
     879  function SendAndMail($from) {
     880    $this->error = null; # so no confusion is caused
    870881
    871         fputs($this->smtp_conn,"SAML FROM:" . $from . $this->CRLF);
     882    if(!$this->connected()) {
     883      $this->error = array(
     884          "error" => "Called SendAndMail() without being connected");
     885      return false;
     886    }
    872887
    873         $rply = $this->get_lines();
    874         $code = substr($rply,0,3);
     888    fputs($this->smtp_conn,"SAML FROM:" . $from . $this->CRLF);
    875889
    876         if($this->do_debug >= 2) {
    877             echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
    878         }
     890    $rply = $this->get_lines();
     891    $code = substr($rply,0,3);
    879892
    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;
     893    if($this->do_debug >= 2) {
     894      echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
    892895    }
    893896
    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
     897    if($code != 250) {
     898      $this->error =
     899        array("error" => "SAML not accepted from server",
     900              "smtp_code" => $code,
     901              "smtp_msg" => substr($rply,4));
     902      if($this->do_debug >= 1) {
     903        echo "SMTP -> ERROR: " . $this->error["error"] .
     904                 ": " . $rply . $this->CRLF;
     905      }
     906      return false;
     907    }
     908    return true;
     909  }
    912910
    913         if(!$this->connected()) {
    914             $this->error = array(
    915                 "error" => "Called SendOrMail() without being connected");
    916             return false;
    917         }
     911  /**
     912   * Starts a mail transaction from the email address specified in
     913   * $from. Returns true if successful or false otherwise. If True
     914   * the mail transaction is started and then one or more Recipient
     915   * commands may be called followed by a Data command. This command
     916   * will send the message to the users terminal if they are logged
     917   * in or mail it to them if they are not.
     918   *
     919   * Implements rfc 821: SOML <SP> FROM:<reverse-path> <CRLF>
     920   *
     921   * SMTP CODE SUCCESS: 250
     922   * SMTP CODE SUCCESS: 552,451,452
     923   * SMTP CODE SUCCESS: 500,501,502,421
     924   * @access public
     925   * @return bool
     926   */
     927  function SendOrMail($from) {
     928    $this->error = null; # so no confusion is caused
    918929
    919         fputs($this->smtp_conn,"SOML FROM:" . $from . $this->CRLF);
     930    if(!$this->connected()) {
     931      $this->error = array(
     932          "error" => "Called SendOrMail() without being connected");
     933      return false;
     934    }
    920935
    921         $rply = $this->get_lines();
    922         $code = substr($rply,0,3);
     936    fputs($this->smtp_conn,"SOML FROM:" . $from . $this->CRLF);
    923937
    924         if($this->do_debug >= 2) {
    925             echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
    926         }
     938    $rply = $this->get_lines();
     939    $code = substr($rply,0,3);
    927940
    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;
     941    if($this->do_debug >= 2) {
     942      echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
    940943    }
    941944
    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;
     945    if($code != 250) {
     946      $this->error =
     947        array("error" => "SOML not accepted from server",
     948              "smtp_code" => $code,
     949              "smtp_msg" => substr($rply,4));
     950      if($this->do_debug >= 1) {
     951        echo "SMTP -> ERROR: " . $this->error["error"] .
     952                 ": " . $rply . $this->CRLF;
     953      }
     954      return false;