CodeIgniter PHP Cross Reference Developer Tools

Source: /system/libraries/Email.php - 2092 lines - 47983 bytes - Summary - Text - Print

Description: CodeIgniter An open source application development framework for PHP 5.1.6 or newer

   1  <?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
   2  /**
   3   * CodeIgniter
   4   *
   5   * An open source application development framework for PHP 5.1.6 or newer
   6   *
   7   * @package        CodeIgniter
   8   * @author        ExpressionEngine Dev Team
   9   * @copyright    Copyright (c) 2008 - 2011, EllisLab, Inc.
  10   * @license        http://codeigniter.com/user_guide/license.html
  11   * @link        http://codeigniter.com
  12   * @since        Version 1.0
  13   * @filesource
  14   */
  15  
  16  // ------------------------------------------------------------------------
  17  
  18  /**
  19   * CodeIgniter Email Class
  20   *
  21   * Permits email to be sent using Mail, Sendmail, or SMTP.
  22   *
  23   * @package        CodeIgniter
  24   * @subpackage    Libraries
  25   * @category    Libraries
  26   * @author        ExpressionEngine Dev Team
  27   * @link        http://codeigniter.com/user_guide/libraries/email.html
  28   */
  29  class CI_Email {
  30  
  31      var    $useragent        = "CodeIgniter";
  32      var    $mailpath        = "/usr/sbin/sendmail";    // Sendmail path
  33      var    $protocol        = "mail";    // mail/sendmail/smtp
  34      var    $smtp_host        = "";        // SMTP Server.  Example: mail.earthlink.net
  35      var    $smtp_user        = "";        // SMTP Username
  36      var    $smtp_pass        = "";        // SMTP Password
  37      var    $smtp_port        = "25";        // SMTP Port
  38      var    $smtp_timeout    = 5;        // SMTP Timeout in seconds
  39      var    $smtp_crypto    = "";        // SMTP Encryption. Can be null, tls or ssl.
  40      var    $wordwrap        = TRUE;        // TRUE/FALSE  Turns word-wrap on/off
  41      var    $wrapchars        = "76";        // Number of characters to wrap at.
  42      var    $mailtype        = "text";    // text/html  Defines email formatting
  43      var    $charset        = "utf-8";    // Default char set: iso-8859-1 or us-ascii
  44      var    $multipart        = "mixed";    // "mixed" (in the body) or "related" (separate)
  45      var $alt_message    = '';        // Alternative message for HTML emails
  46      var    $validate        = FALSE;    // TRUE/FALSE.  Enables email validation
  47      var    $priority        = "3";        // Default priority (1 - 5)
  48      var    $newline        = "\n";        // Default newline. "\r\n" or "\n" (Use "\r\n" to comply with RFC 822)
  49      var $crlf            = "\n";        // The RFC 2045 compliant CRLF for quoted-printable is "\r\n".  Apparently some servers,
  50                                      // even on the receiving end think they need to muck with CRLFs, so using "\n", while
  51                                      // distasteful, is the only thing that seems to work for all environments.
  52      var $send_multipart    = TRUE;        // TRUE/FALSE - Yahoo does not like multipart alternative, so this is an override.  Set to FALSE for Yahoo.
  53      var    $bcc_batch_mode    = FALSE;    // TRUE/FALSE  Turns on/off Bcc batch feature
  54      var    $bcc_batch_size    = 200;        // If bcc_batch_mode = TRUE, sets max number of Bccs in each batch
  55      var $_safe_mode        = FALSE;
  56      var    $_subject        = "";
  57      var    $_body            = "";
  58      var    $_finalbody        = "";
  59      var    $_alt_boundary    = "";
  60      var    $_atc_boundary    = "";
  61      var    $_header_str    = "";
  62      var    $_smtp_connect    = "";
  63      var    $_encoding        = "8bit";
  64      var $_IP            = FALSE;
  65      var    $_smtp_auth        = FALSE;
  66      var $_replyto_flag    = FALSE;
  67      var    $_debug_msg        = array();
  68      var    $_recipients    = array();
  69      var    $_cc_array        = array();
  70      var    $_bcc_array        = array();
  71      var    $_headers        = array();
  72      var    $_attach_name    = array();
  73      var    $_attach_type    = array();
  74      var    $_attach_disp    = array();
  75      var    $_protocols        = array('mail', 'sendmail', 'smtp');
  76      var    $_base_charsets    = array('us-ascii', 'iso-2022-');    // 7-bit charsets (excluding language suffix)
  77      var    $_bit_depths    = array('7bit', '8bit');
  78      var    $_priorities    = array('1 (Highest)', '2 (High)', '3 (Normal)', '4 (Low)', '5 (Lowest)');
  79  
  80  
  81      /**
  82       * Constructor - Sets Email Preferences
  83       *
  84       * The constructor can be passed an array of config values
  85       */
  86  	public function __construct($config = array())
  87      {
  88          if (count($config) > 0)
  89          {
  90              $this->initialize($config);
  91          }
  92          else
  93          {
  94              $this->_smtp_auth = ($this->smtp_user == '' AND $this->smtp_pass == '') ? FALSE : TRUE;
  95              $this->_safe_mode = ((boolean)@ini_get("safe_mode") === FALSE) ? FALSE : TRUE;
  96          }
  97  
  98          log_message('debug', "Email Class Initialized");
  99      }
 100  
 101      // --------------------------------------------------------------------
 102  
 103      /**
 104       * Initialize preferences
 105       *
 106       * @access    public
 107       * @param    array
 108       * @return    void
 109       */
 110  	public function initialize($config = array())
 111      {
 112          foreach ($config as $key => $val)
 113          {
 114              if (isset($this->$key))
 115              {
 116                  $method = 'set_'.$key;
 117  
 118                  if (method_exists($this, $method))
 119                  {
 120                      $this->$method($val);
 121                  }
 122                  else
 123                  {
 124                      $this->$key = $val;
 125                  }
 126              }
 127          }
 128          $this->clear();
 129  
 130          $this->_smtp_auth = ($this->smtp_user == '' AND $this->smtp_pass == '') ? FALSE : TRUE;
 131          $this->_safe_mode = ((boolean)@ini_get("safe_mode") === FALSE) ? FALSE : TRUE;
 132  
 133          return $this;
 134      }
 135  
 136      // --------------------------------------------------------------------
 137  
 138      /**
 139       * Initialize the Email Data
 140       *
 141       * @access    public
 142       * @return    void
 143       */
 144  	public function clear($clear_attachments = FALSE)
 145      {
 146          $this->_subject        = "";
 147          $this->_body        = "";
 148          $this->_finalbody    = "";
 149          $this->_header_str    = "";
 150          $this->_replyto_flag = FALSE;
 151          $this->_recipients    = array();
 152          $this->_cc_array    = array();
 153          $this->_bcc_array    = array();
 154          $this->_headers        = array();
 155          $this->_debug_msg    = array();
 156  
 157          $this->_set_header('User-Agent', $this->useragent);
 158          $this->_set_header('Date', $this->_set_date());
 159  
 160          if ($clear_attachments !== FALSE)
 161          {
 162              $this->_attach_name = array();
 163              $this->_attach_type = array();
 164              $this->_attach_disp = array();
 165          }
 166  
 167          return $this;
 168      }
 169  
 170      // --------------------------------------------------------------------
 171  
 172      /**
 173       * Set FROM
 174       *
 175       * @access    public
 176       * @param    string
 177       * @param    string
 178       * @return    void
 179       */
 180  	public function from($from, $name = '')
 181      {
 182          if (preg_match( '/\<(.*)\>/', $from, $match))
 183          {
 184              $from = $match['1'];
 185          }
 186  
 187          if ($this->validate)
 188          {
 189              $this->validate_email($this->_str_to_array($from));
 190          }
 191  
 192          // prepare the display name
 193          if ($name != '')
 194          {
 195              // only use Q encoding if there are characters that would require it
 196              if ( ! preg_match('/[\200-\377]/', $name))
 197              {
 198                  // add slashes for non-printing characters, slashes, and double quotes, and surround it in double quotes
 199                  $name = '"'.addcslashes($name, "\0..\37\177'\"\\").'"';
 200              }
 201              else
 202              {
 203                  $name = $this->_prep_q_encoding($name, TRUE);
 204              }
 205          }
 206  
 207          $this->_set_header('From', $name.' <'.$from.'>');
 208          $this->_set_header('Return-Path', '<'.$from.'>');
 209  
 210          return $this;
 211      }
 212  
 213      // --------------------------------------------------------------------
 214  
 215      /**
 216       * Set Reply-to
 217       *
 218       * @access    public
 219       * @param    string
 220       * @param    string
 221       * @return    void
 222       */
 223  	public function reply_to($replyto, $name = '')
 224      {
 225          if (preg_match( '/\<(.*)\>/', $replyto, $match))
 226          {
 227              $replyto = $match['1'];
 228          }
 229  
 230          if ($this->validate)
 231          {
 232              $this->validate_email($this->_str_to_array($replyto));
 233          }
 234  
 235          if ($name == '')
 236          {
 237              $name = $replyto;
 238          }
 239  
 240          if (strncmp($name, '"', 1) != 0)
 241          {
 242              $name = '"'.$name.'"';
 243          }
 244  
 245          $this->_set_header('Reply-To', $name.' <'.$replyto.'>');
 246          $this->_replyto_flag = TRUE;
 247  
 248          return $this;
 249      }
 250  
 251      // --------------------------------------------------------------------
 252  
 253      /**
 254       * Set Recipients
 255       *
 256       * @access    public
 257       * @param    string
 258       * @return    void
 259       */
 260      public function to($to)
 261      {
 262          $to = $this->_str_to_array($to);
 263          $to = $this->clean_email($to);
 264  
 265          if ($this->validate)
 266          {
 267              $this->validate_email($to);
 268          }
 269  
 270          if ($this->_get_protocol() != 'mail')
 271          {
 272              $this->_set_header('To', implode(", ", $to));
 273          }
 274  
 275          switch ($this->_get_protocol())
 276          {
 277              case 'smtp'        :
 278                  $this->_recipients = $to;
 279              break;
 280              case 'sendmail'    :
 281              case 'mail'        :
 282                  $this->_recipients = implode(", ", $to);
 283              break;
 284          }
 285  
 286          return $this;
 287      }
 288  
 289      // --------------------------------------------------------------------
 290  
 291      /**
 292       * Set CC
 293       *
 294       * @access    public
 295       * @param    string
 296       * @return    void
 297       */
 298      public function cc($cc)
 299      {
 300          $cc = $this->_str_to_array($cc);
 301          $cc = $this->clean_email($cc);
 302  
 303          if ($this->validate)
 304          {
 305              $this->validate_email($cc);
 306          }
 307  
 308          $this->_set_header('Cc', implode(", ", $cc));
 309  
 310          if ($this->_get_protocol() == "smtp")
 311          {
 312              $this->_cc_array = $cc;
 313          }
 314  
 315          return $this;
 316      }
 317  
 318      // --------------------------------------------------------------------
 319  
 320      /**
 321       * Set BCC
 322       *
 323       * @access    public
 324       * @param    string
 325       * @param    string
 326       * @return    void
 327       */
 328  	public function bcc($bcc, $limit = '')
 329      {
 330          if ($limit != '' && is_numeric($limit))
 331          {
 332              $this->bcc_batch_mode = TRUE;
 333              $this->bcc_batch_size = $limit;
 334          }
 335  
 336          $bcc = $this->_str_to_array($bcc);
 337          $bcc = $this->clean_email($bcc);
 338  
 339          if ($this->validate)
 340          {
 341              $this->validate_email($bcc);
 342          }
 343  
 344          if (($this->_get_protocol() == "smtp") OR ($this->bcc_batch_mode && count($bcc) > $this->bcc_batch_size))
 345          {
 346              $this->_bcc_array = $bcc;
 347          }
 348          else
 349          {
 350              $this->_set_header('Bcc', implode(", ", $bcc));
 351          }
 352  
 353          return $this;
 354      }
 355  
 356      // --------------------------------------------------------------------
 357  
 358      /**
 359       * Set Email Subject
 360       *
 361       * @access    public
 362       * @param    string
 363       * @return    void
 364       */
 365  	public function subject($subject)
 366      {
 367          $subject = $this->_prep_q_encoding($subject);
 368          $this->_set_header('Subject', $subject);
 369          return $this;
 370      }
 371  
 372      // --------------------------------------------------------------------
 373  
 374      /**
 375       * Set Body
 376       *
 377       * @access    public
 378       * @param    string
 379       * @return    void
 380       */
 381  	public function message($body)
 382      {
 383          $this->_body = rtrim(str_replace("\r", "", $body));
 384  
 385          /* strip slashes only if magic quotes is ON
 386             if we do it with magic quotes OFF, it strips real, user-inputted chars.
 387  
 388             NOTE: In PHP 5.4 get_magic_quotes_gpc() will always return 0 and
 389               it will probably not exist in future versions at all.
 390          */
 391          if ( ! is_php('5.4') && get_magic_quotes_gpc())
 392          {
 393              $this->_body = stripslashes($this->_body);
 394          }
 395  
 396          return $this;
 397      }
 398  
 399      // --------------------------------------------------------------------
 400  
 401      /**
 402       * Assign file attachments
 403       *
 404       * @access    public
 405       * @param    string
 406       * @return    void
 407       */
 408  	public function attach($filename, $disposition = 'attachment')
 409      {
 410          $this->_attach_name[] = $filename;
 411          $this->_attach_type[] = $this->_mime_types(pathinfo($filename, PATHINFO_EXTENSION));
 412          $this->_attach_disp[] = $disposition; // Can also be 'inline'  Not sure if it matters
 413          return $this;
 414      }
 415  
 416      // --------------------------------------------------------------------
 417  
 418      /**
 419       * Add a Header Item
 420       *
 421       * @access    protected
 422       * @param    string
 423       * @param    string
 424       * @return    void
 425       */
 426  	protected function _set_header($header, $value)
 427      {
 428          $this->_headers[$header] = $value;
 429      }
 430  
 431      // --------------------------------------------------------------------
 432  
 433      /**
 434       * Convert a String to an Array
 435       *
 436       * @access    protected
 437       * @param    string
 438       * @return    array
 439       */
 440  	protected function _str_to_array($email)
 441      {
 442          if ( ! is_array($email))
 443          {
 444              if (strpos($email, ',') !== FALSE)
 445              {
 446                  $email = preg_split('/[\s,]/', $email, -1, PREG_SPLIT_NO_EMPTY);
 447              }
 448              else
 449              {
 450                  $email = trim($email);
 451                  settype($email, "array");
 452              }
 453          }
 454          return $email;
 455      }
 456  
 457      // --------------------------------------------------------------------
 458  
 459      /**
 460       * Set Multipart Value
 461       *
 462       * @access    public
 463       * @param    string
 464       * @return    void
 465       */
 466  	public function set_alt_message($str = '')
 467      {
 468          $this->alt_message = $str;
 469          return $this;
 470      }
 471  
 472      // --------------------------------------------------------------------
 473  
 474      /**
 475       * Set Mailtype
 476       *
 477       * @access    public
 478       * @param    string
 479       * @return    void
 480       */
 481  	public function set_mailtype($type = 'text')
 482      {
 483          $this->mailtype = ($type == 'html') ? 'html' : 'text';
 484          return $this;
 485      }
 486  
 487      // --------------------------------------------------------------------
 488  
 489      /**
 490       * Set Wordwrap
 491       *
 492       * @access    public
 493       * @param    string
 494       * @return    void
 495       */
 496  	public function set_wordwrap($wordwrap = TRUE)
 497      {
 498          $this->wordwrap = ($wordwrap === FALSE) ? FALSE : TRUE;
 499          return $this;
 500      }
 501  
 502      // --------------------------------------------------------------------
 503  
 504      /**
 505       * Set Protocol
 506       *
 507       * @access    public
 508       * @param    string
 509       * @return    void
 510       */
 511  	public function set_protocol($protocol = 'mail')
 512      {
 513          $this->protocol = ( ! in_array($protocol, $this->_protocols, TRUE)) ? 'mail' : strtolower($protocol);
 514          return $this;
 515      }
 516  
 517      // --------------------------------------------------------------------
 518  
 519      /**
 520       * Set Priority
 521       *
 522       * @access    public
 523       * @param    integer
 524       * @return    void
 525       */
 526  	public function set_priority($n = 3)
 527      {
 528          if ( ! is_numeric($n))
 529          {
 530              $this->priority = 3;
 531              return;
 532          }
 533  
 534          if ($n < 1 OR $n > 5)
 535          {
 536              $this->priority = 3;
 537              return;
 538          }
 539  
 540          $this->priority = $n;
 541          return $this;
 542      }
 543  
 544      // --------------------------------------------------------------------
 545  
 546      /**
 547       * Set Newline Character
 548       *
 549       * @access    public
 550       * @param    string
 551       * @return    void
 552       */
 553  	public function set_newline($newline = "\n")
 554      {
 555          if ($newline != "\n" AND $newline != "\r\n" AND $newline != "\r")
 556          {
 557              $this->newline    = "\n";
 558              return;
 559          }
 560  
 561          $this->newline    = $newline;
 562  
 563          return $this;
 564      }
 565  
 566      // --------------------------------------------------------------------
 567  
 568      /**
 569       * Set CRLF
 570       *
 571       * @access    public
 572       * @param    string
 573       * @return    void
 574       */
 575  	public function set_crlf($crlf = "\n")
 576      {
 577          if ($crlf != "\n" AND $crlf != "\r\n" AND $crlf != "\r")
 578          {
 579              $this->crlf    = "\n";
 580              return;
 581          }
 582  
 583          $this->crlf    = $crlf;
 584  
 585          return $this;
 586      }
 587  
 588      // --------------------------------------------------------------------
 589  
 590      /**
 591       * Set Message Boundary
 592       *
 593       * @access    protected
 594       * @return    void
 595       */
 596  	protected function _set_boundaries()
 597      {
 598          $this->_alt_boundary = "B_ALT_".uniqid(''); // multipart/alternative
 599          $this->_atc_boundary = "B_ATC_".uniqid(''); // attachment boundary
 600      }
 601  
 602      // --------------------------------------------------------------------
 603  
 604      /**
 605       * Get the Message ID
 606       *
 607       * @access    protected
 608       * @return    string
 609       */
 610  	protected function _get_message_id()
 611      {
 612          $from = $this->_headers['Return-Path'];
 613          $from = str_replace(">", "", $from);
 614          $from = str_replace("<", "", $from);
 615  
 616          return  "<".uniqid('').strstr($from, '@').">";
 617      }
 618  
 619      // --------------------------------------------------------------------
 620  
 621      /**
 622       * Get Mail Protocol
 623       *
 624       * @access    protected
 625       * @param    bool
 626       * @return    string
 627       */
 628  	protected function _get_protocol($return = TRUE)
 629      {
 630          $this->protocol = strtolower($this->protocol);
 631          $this->protocol = ( ! in_array($this->protocol, $this->_protocols, TRUE)) ? 'mail' : $this->protocol;
 632  
 633          if ($return == TRUE)
 634          {
 635              return $this->protocol;
 636          }
 637      }
 638  
 639      // --------------------------------------------------------------------
 640  
 641      /**
 642       * Get Mail Encoding
 643       *
 644       * @access    protected
 645       * @param    bool
 646       * @return    string
 647       */
 648  	protected function _get_encoding($return = TRUE)
 649      {
 650          $this->_encoding = ( ! in_array($this->_encoding, $this->_bit_depths)) ? '8bit' : $this->_encoding;
 651  
 652          foreach ($this->_base_charsets as $charset)
 653          {
 654              if (strncmp($charset, $this->charset, strlen($charset)) == 0)
 655              {
 656                  $this->_encoding = '7bit';
 657              }
 658          }
 659  
 660          if ($return == TRUE)
 661          {
 662              return $this->_encoding;
 663          }
 664      }
 665  
 666      // --------------------------------------------------------------------
 667  
 668      /**
 669       * Get content type (text/html/attachment)
 670       *
 671       * @access    protected
 672       * @return    string
 673       */
 674  	protected function _get_content_type()
 675      {
 676          if    ($this->mailtype == 'html' &&  count($this->_attach_name) == 0)
 677          {
 678              return 'html';
 679          }
 680          elseif    ($this->mailtype == 'html' &&  count($this->_attach_name)  > 0)
 681          {
 682              return 'html-attach';
 683          }
 684          elseif    ($this->mailtype == 'text' &&  count($this->_attach_name)  > 0)
 685          {
 686              return 'plain-attach';
 687          }
 688          else
 689          {
 690              return 'plain';
 691          }
 692      }
 693  
 694      // --------------------------------------------------------------------
 695  
 696      /**
 697       * Set RFC 822 Date
 698       *
 699       * @access    protected
 700       * @return    string
 701       */
 702  	protected function _set_date()
 703      {
 704          $timezone = date("Z");
 705          $operator = (strncmp($timezone, '-', 1) == 0) ? '-' : '+';
 706          $timezone = abs($timezone);
 707          $timezone = floor($timezone/3600) * 100 + ($timezone % 3600 ) / 60;
 708  
 709          return sprintf("%s %s%04d", date("D, j M Y H:i:s"), $operator, $timezone);
 710      }
 711  
 712      // --------------------------------------------------------------------
 713  
 714      /**
 715       * Mime message
 716       *
 717       * @access    protected
 718       * @return    string
 719       */
 720  	protected function _get_mime_message()
 721      {
 722          return "This is a multi-part message in MIME format.".$this->newline."Your email application may not support this format.";
 723      }
 724  
 725      // --------------------------------------------------------------------
 726  
 727      /**
 728       * Validate Email Address
 729       *
 730       * @access    public
 731       * @param    string
 732       * @return    bool
 733       */
 734  	public function validate_email($email)
 735      {
 736          if ( ! is_array($email))
 737          {
 738              $this->_set_error_message('lang:email_must_be_array');
 739              return FALSE;
 740          }
 741  
 742          foreach ($email as $val)
 743          {
 744              if ( ! $this->valid_email($val))
 745              {
 746                  $this->_set_error_message('lang:email_invalid_address', $val);
 747                  return FALSE;
 748              }
 749          }
 750  
 751          return TRUE;
 752      }
 753  
 754      // --------------------------------------------------------------------
 755  
 756      /**
 757       * Email Validation
 758       *
 759       * @access    public
 760       * @param    string
 761       * @return    bool
 762       */
 763  	public function valid_email($address)
 764      {
 765          return ( ! preg_match("/^([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*@([a-z0-9\-]+\.)+[a-z]{2,6}$/ix", $address)) ? FALSE : TRUE;
 766      }
 767  
 768      // --------------------------------------------------------------------
 769  
 770      /**
 771       * Clean Extended Email Address: Joe Smith <joe@smith.com>
 772       *
 773       * @access    public
 774       * @param    string
 775       * @return    string
 776       */
 777  	public function clean_email($email)
 778      {
 779          if ( ! is_array($email))
 780          {
 781              if (preg_match('/\<(.*)\>/', $email, $match))
 782              {
 783                  return $match['1'];
 784              }
 785              else
 786              {
 787                  return $email;
 788              }
 789          }
 790  
 791          $clean_email = array();
 792  
 793          foreach ($email as $addy)
 794          {
 795              if (preg_match( '/\<(.*)\>/', $addy, $match))
 796              {
 797                  $clean_email[] = $match['1'];
 798              }
 799              else
 800              {
 801                  $clean_email[] = $addy;
 802              }
 803          }
 804  
 805          return $clean_email;
 806      }
 807  
 808      // --------------------------------------------------------------------
 809  
 810      /**
 811       * Build alternative plain text message
 812       *
 813       * This public function provides the raw message for use
 814       * in plain-text headers of HTML-formatted emails.
 815       * If the user hasn't specified his own alternative message
 816       * it creates one by stripping the HTML
 817       *
 818       * @access    protected
 819       * @return    string
 820       */
 821  	protected function _get_alt_message()
 822      {
 823          if ($this->alt_message != "")
 824          {
 825              return $this->word_wrap($this->alt_message, '76');
 826          }
 827  
 828          if (preg_match('/\<body.*?\>(.*)\<\/body\>/si', $this->_body, $match))
 829          {
 830              $body = $match['1'];
 831          }
 832          else
 833          {
 834              $body = $this->_body;
 835          }
 836  
 837          $body = trim(strip_tags($body));
 838          $body = preg_replace( '#<!--(.*)--\>#', "", $body);
 839          $body = str_replace("\t", "", $body);
 840  
 841          for ($i = 20; $i >= 3; $i--)
 842          {
 843              $n = "";
 844  
 845              for ($x = 1; $x <= $i; $x ++)
 846              {
 847                  $n .= "\n";
 848              }
 849  
 850              $body = str_replace($n, "\n\n", $body);
 851          }
 852  
 853          return $this->word_wrap($body, '76');
 854      }
 855  
 856      // --------------------------------------------------------------------
 857  
 858      /**
 859       * Word Wrap
 860       *
 861       * @access    public
 862       * @param    string
 863       * @param    integer
 864       * @return    string
 865       */
 866  	public function word_wrap($str, $charlim = '')
 867      {
 868          // Se the character limit
 869          if ($charlim == '')
 870          {
 871              $charlim = ($this->wrapchars == "") ? "76" : $this->wrapchars;
 872          }
 873  
 874          // Reduce multiple spaces
 875          $str = preg_replace("| +|", " ", $str);
 876  
 877          // Standardize newlines
 878          if (strpos($str, "\r") !== FALSE)
 879          {
 880              $str = str_replace(array("\r\n", "\r"), "\n", $str);
 881          }
 882  
 883          // If the current word is surrounded by {unwrap} tags we'll
 884          // strip the entire chunk and replace it with a marker.
 885          $unwrap = array();
 886          if (preg_match_all("|(\{unwrap\}.+?\{/unwrap\})|s", $str, $matches))
 887          {
 888              for ($i = 0; $i < count($matches['0']); $i++)
 889              {
 890                  $unwrap[] = $matches['1'][$i];
 891                  $str = str_replace($matches['1'][$i], "{{unwrapped".$i."}}", $str);
 892              }
 893          }
 894  
 895          // Use PHP's native public function to do the initial wordwrap.
 896          // We set the cut flag to FALSE so that any individual words that are
 897          // too long get left alone.  In the next step we'll deal with them.
 898          $str = wordwrap($str, $charlim, "\n", FALSE);
 899  
 900          // Split the string into individual lines of text and cycle through them
 901          $output = "";
 902          foreach (explode("\n", $str) as $line)
 903          {
 904              // Is the line within the allowed character count?
 905              // If so we'll join it to the output and continue
 906              if (strlen($line) <= $charlim)
 907              {
 908                  $output .= $line.$this->newline;
 909                  continue;
 910              }
 911  
 912              $temp = '';
 913              while ((strlen($line)) > $charlim)
 914              {
 915                  // If the over-length word is a URL we won't wrap it
 916                  if (preg_match("!\[url.+\]|://|wwww.!", $line))
 917                  {
 918                      break;
 919                  }
 920  
 921                  // Trim the word down
 922                  $temp .= substr($line, 0, $charlim-1);
 923                  $line = substr($line, $charlim-1);
 924              }
 925  
 926              // If $temp contains data it means we had to split up an over-length
 927              // word into smaller chunks so we'll add it back to our current line
 928              if ($temp != '')
 929              {
 930                  $output .= $temp.$this->newline.$line;
 931              }
 932              else
 933              {
 934                  $output .= $line;
 935              }
 936  
 937              $output .= $this->newline;
 938          }
 939  
 940          // Put our markers back
 941          if (count($unwrap) > 0)
 942          {
 943              foreach ($unwrap as $key => $val)
 944              {
 945                  $output = str_replace("{{unwrapped".$key."}}", $val, $output);
 946              }
 947          }
 948  
 949          return $output;
 950      }
 951  
 952      // --------------------------------------------------------------------
 953  
 954      /**
 955       * Build final headers
 956       *
 957       * @access    protected
 958       * @param    string
 959       * @return    string
 960       */
 961  	protected function _build_headers()
 962      {
 963          $this->_set_header('X-Sender', $this->clean_email($this->_headers['From']));
 964          $this->_set_header('X-Mailer', $this->useragent);
 965          $this->_set_header('X-Priority', $this->_priorities[$this->priority - 1]);
 966          $this->_set_header('Message-ID', $this->_get_message_id());
 967          $this->_set_header('Mime-Version', '1.0');
 968      }
 969  
 970      // --------------------------------------------------------------------
 971  
 972      /**
 973       * Write Headers as a string
 974       *
 975       * @access    protected
 976       * @return    void
 977       */
 978  	protected function _write_headers()
 979      {
 980          if ($this->protocol == 'mail')
 981          {
 982              $this->_subject = $this->_headers['Subject'];
 983              unset($this->_headers['Subject']);
 984          }
 985  
 986          reset($this->_headers);
 987          $this->_header_str = "";
 988  
 989          foreach ($this->_headers as $key => $val)
 990          {
 991              $val = trim($val);
 992  
 993              if ($val != "")
 994              {
 995                  $this->_header_str .= $key.": ".$val.$this->newline;
 996              }
 997          }
 998  
 999          if ($this->_get_protocol() == 'mail')
1000          {
1001              $this->_header_str = rtrim($this->_header_str);
1002          }
1003      }
1004  
1005      // --------------------------------------------------------------------
1006  
1007      /**
1008       * Build Final Body and attachments
1009       *
1010       * @access    protected
1011       * @return    void
1012       */
1013  	protected function _build_message()
1014      {
1015          if ($this->wordwrap === TRUE  AND  $this->mailtype != 'html')
1016          {
1017              $this->_body = $this->word_wrap($this->_body);
1018          }
1019  
1020          $this->_set_boundaries();
1021          $this->_write_headers();
1022  
1023          $hdr = ($this->_get_protocol() == 'mail') ? $this->newline : '';
1024          $body = '';
1025  
1026          switch ($this->_get_content_type())
1027          {
1028              case 'plain' :
1029  
1030                  $hdr .= "Content-Type: text/plain; charset=" . $this->charset . $this->newline;
1031                  $hdr .= "Content-Transfer-Encoding: " . $this->_get_encoding();
1032  
1033                  if ($this->_get_protocol() == 'mail')
1034                  {
1035                      $this->_header_str .= $hdr;
1036                      $this->_finalbody = $this->_body;
1037                  }
1038                  else
1039                  {
1040                      $this->_finalbody = $hdr . $this->newline . $this->newline . $this->_body;
1041                  }
1042  
1043                  return;
1044  
1045              break;
1046              case 'html' :
1047  
1048                  if ($this->send_multipart === FALSE)
1049                  {
1050                      $hdr .= "Content-Type: text/html; charset=" . $this->charset . $this->newline;
1051                      $hdr .= "Content-Transfer-Encoding: quoted-printable";
1052                  }
1053                  else
1054                  {
1055                      $hdr .= "Content-Type: multipart/alternative; boundary=\"" . $this->_alt_boundary . "\"" . $this->newline . $this->newline;
1056  
1057                      $body .= $this->_get_mime_message() . $this->newline . $this->newline;
1058                      $body .= "--" . $this->_alt_boundary . $this->newline;
1059  
1060                      $body .= "Content-Type: text/plain; charset=" . $this->charset . $this->newline;
1061                      $body .= "Content-Transfer-Encoding: " . $this->_get_encoding() . $this->newline . $this->newline;
1062                      $body .= $this->_get_alt_message() . $this->newline . $this->newline . "--" . $this->_alt_boundary . $this->newline;
1063  
1064                      $body .= "Content-Type: text/html; charset=" . $this->charset . $this->newline;
1065                      $body .= "Content-Transfer-Encoding: quoted-printable" . $this->newline . $this->newline;
1066                  }
1067  
1068                  $this->_finalbody = $body . $this->_prep_quoted_printable($this->_body) . $this->newline . $this->newline;
1069  
1070  
1071                  if ($this->_get_protocol() == 'mail')
1072                  {
1073                      $this->_header_str .= $hdr;
1074                  }
1075                  else
1076                  {
1077                      $this->_finalbody = $hdr . $this->_finalbody;
1078                  }
1079  
1080  
1081                  if ($this->send_multipart !== FALSE)
1082                  {
1083                      $this->_finalbody .= "--" . $this->_alt_boundary . "--";
1084                  }
1085  
1086                  return;
1087  
1088              break;
1089              case 'plain-attach' :
1090  
1091                  $hdr .= "Content-Type: multipart/".$this->multipart."; boundary=\"" . $this->_atc_boundary."\"" . $this->newline . $this->newline;
1092  
1093                  if ($this->_get_protocol() == 'mail')
1094                  {
1095                      $this->_header_str .= $hdr;
1096                  }
1097  
1098                  $body .= $this->_get_mime_message() . $this->newline . $this->newline;
1099                  $body .= "--" . $this->_atc_boundary . $this->newline;
1100  
1101                  $body .= "Content-Type: text/plain; charset=" . $this->charset . $this->newline;
1102                  $body .= "Content-Transfer-Encoding: " . $this->_get_encoding() . $this->newline . $this->newline;
1103  
1104                  $body .= $this->_body . $this->newline . $this->newline;
1105  
1106              break;
1107              case 'html-attach' :
1108  
1109                  $hdr .= "Content-Type: multipart/".$this->multipart."; boundary=\"" . $this->_atc_boundary."\"" . $this->newline . $this->newline;
1110  
1111                  if ($this->_get_protocol() == 'mail')
1112                  {
1113                      $this->_header_str .= $hdr;
1114                  }
1115  
1116                  $body .= $this->_get_mime_message() . $this->newline . $this->newline;
1117                  $body .= "--" . $this->_atc_boundary . $this->newline;
1118  
1119                  $body .= "Content-Type: multipart/alternative; boundary=\"" . $this->_alt_boundary . "\"" . $this->newline .$this->newline;
1120                  $body .= "--" . $this->_alt_boundary . $this->newline;
1121  
1122                  $body .= "Content-Type: text/plain; charset=" . $this->charset . $this->newline;
1123                  $body .= "Content-Transfer-Encoding: " . $this->_get_encoding() . $this->newline . $this->newline;
1124                  $body .= $this->_get_alt_message() . $this->newline . $this->newline . "--" . $this->_alt_boundary . $this->newline;
1125  
1126                  $body .= "Content-Type: text/html; charset=" . $this->charset . $this->newline;
1127                  $body .= "Content-Transfer-Encoding: quoted-printable" . $this->newline . $this->newline;
1128  
1129                  $body .= $this->_prep_quoted_printable($this->_body) . $this->newline . $this->newline;
1130                  $body .= "--" . $this->_alt_boundary . "--" . $this->newline . $this->newline;
1131  
1132              break;
1133          }
1134  
1135          $attachment = array();
1136  
1137          $z = 0;
1138  
1139          for ($i=0; $i < count($this->_attach_name); $i++)
1140          {
1141              $filename = $this->_attach_name[$i];
1142              $basename = basename($filename);
1143              $ctype = $this->_attach_type[$i];
1144  
1145              if ( ! file_exists($filename))
1146              {
1147                  $this->_set_error_message('lang:email_attachment_missing', $filename);
1148                  return FALSE;
1149              }
1150  
1151              $h  = "--".$this->_atc_boundary.$this->newline;
1152              $h .= "Content-type: ".$ctype."; ";
1153              $h .= "name=\"".$basename."\"".$this->newline;
1154              $h .= "Content-Disposition: ".$this->_attach_disp[$i].";".$this->newline;
1155              $h .= "Content-Transfer-Encoding: base64".$this->newline;
1156  
1157              $attachment[$z++] = $h;
1158              $file = filesize($filename) +1;
1159  
1160              if ( ! $fp = fopen($filename, FOPEN_READ))
1161              {
1162                  $this->_set_error_message('lang:email_attachment_unreadable', $filename);
1163                  return FALSE;
1164              }
1165  
1166              $attachment[$z++] = chunk_split(base64_encode(fread($fp, $file)));
1167              fclose($fp);
1168          }
1169  
1170          $body .= implode($this->newline, $attachment).$this->newline."--".$this->_atc_boundary."--";
1171  
1172  
1173          if ($this->_get_protocol() == 'mail')
1174          {
1175              $this->_finalbody = $body;
1176          }
1177          else
1178          {
1179              $this->_finalbody = $hdr . $body;
1180          }
1181  
1182          return;
1183      }
1184  
1185      // --------------------------------------------------------------------
1186  
1187      /**
1188       * Prep Quoted Printable
1189       *
1190       * Prepares string for Quoted-Printable Content-Transfer-Encoding
1191       * Refer to RFC 2045 http://www.ietf.org/rfc/rfc2045.txt
1192       *
1193       * @access    protected
1194       * @param    string
1195       * @param    integer
1196       * @return    string
1197       */
1198  	protected function _prep_quoted_printable($str, $charlim = '')
1199      {
1200          // Set the character limit
1201          // Don't allow over 76, as that will make servers and MUAs barf
1202          // all over quoted-printable data
1203          if ($charlim == '' OR $charlim > '76')
1204          {
1205              $charlim = '76';
1206          }
1207  
1208          // Reduce multiple spaces
1209          $str = preg_replace("| +|", " ", $str);
1210  
1211          // kill nulls
1212          $str = preg_replace('/\x00+/', '', $str);
1213  
1214          // Standardize newlines
1215          if (strpos($str, "\r") !== FALSE)
1216          {
1217              $str = str_replace(array("\r\n", "\r"), "\n", $str);
1218          }
1219  
1220          // We are intentionally wrapping so mail servers will encode characters
1221          // properly and MUAs will behave, so {unwrap} must go!
1222          $str = str_replace(array('{unwrap}', '{/unwrap}'), '', $str);
1223  
1224          // Break into an array of lines
1225          $lines = explode("\n", $str);
1226  
1227          $escape = '=';
1228          $output = '';
1229  
1230          foreach ($lines as $line)
1231          {
1232              $length = strlen($line);
1233              $temp = '';
1234  
1235              // Loop through each character in the line to add soft-wrap
1236              // characters at the end of a line " =\r\n" and add the newly
1237              // processed line(s) to the output (see comment on $crlf class property)
1238              for ($i = 0; $i < $length; $i++)
1239              {
1240                  // Grab the next character
1241                  $char = substr($line, $i, 1);
1242                  $ascii = ord($char);
1243  
1244                  // Convert spaces and tabs but only if it's the end of the line
1245                  if ($i == ($length - 1))
1246                  {
1247                      $char = ($ascii == '32' OR $ascii == '9') ? $escape.sprintf('%02s', dechex($ascii)) : $char;
1248                  }
1249  
1250                  // encode = signs
1251                  if ($ascii == '61')
1252                  {
1253                      $char = $escape.strtoupper(sprintf('%02s', dechex($ascii)));  // =3D
1254                  }
1255  
1256                  // If we're at the character limit, add the line to the output,
1257                  // reset our temp variable, and keep on chuggin'
1258                  if ((strlen($temp) + strlen($char)) >= $charlim)
1259                  {
1260                      $output .= $temp.$escape.$this->crlf;
1261                      $temp = '';
1262                  }
1263  
1264                  // Add the character to our temporary line
1265                  $temp .= $char;
1266              }
1267  
1268              // Add our completed line to the output
1269              $output .= $temp.$this->crlf;
1270          }
1271  
1272          // get rid of extra CRLF tacked onto the end
1273          $output = substr($output, 0, strlen($this->crlf) * -1);
1274  
1275          return $output;
1276      }
1277  
1278      // --------------------------------------------------------------------
1279  
1280      /**
1281       * Prep Q Encoding
1282       *
1283       * Performs "Q Encoding" on a string for use in email headers.  It's related
1284       * but not identical to quoted-printable, so it has its own method
1285       *
1286       * @access    public
1287       * @param    str
1288       * @param    bool    // set to TRUE for processing From: headers
1289       * @return    str
1290       */
1291  	protected function _prep_q_encoding($str, $from = FALSE)
1292      {
1293          $str = str_replace(array("\r", "\n"), array('', ''), $str);
1294  
1295          // Line length must not exceed 76 characters, so we adjust for
1296          // a space, 7 extra characters =??Q??=, and the charset that we will add to each line
1297          $limit = 75 - 7 - strlen($this->charset);
1298  
1299          // these special characters must be converted too
1300          $convert = array('_', '=', '?');
1301  
1302          if ($from === TRUE)
1303          {
1304              $convert[] = ',';
1305              $convert[] = ';';
1306          }
1307  
1308          $output = '';
1309          $temp = '';
1310  
1311          for ($i = 0, $length = strlen($str); $i < $length; $i++)
1312          {
1313              // Grab the next character
1314              $char = substr($str, $i, 1);
1315              $ascii = ord($char);
1316  
1317              // convert ALL non-printable ASCII characters and our specials
1318              if ($ascii < 32 OR $ascii > 126 OR in_array($char, $convert))
1319              {
1320                  $char = '='.dechex($ascii);
1321              }
1322  
1323              // handle regular spaces a bit more compactly than =20
1324              if ($ascii == 32)
1325              {
1326                  $char = '_';
1327              }
1328  
1329              // If we're at the character limit, add the line to the output,
1330              // reset our temp variable, and keep on chuggin'
1331              if ((strlen($temp) + strlen($char)) >= $limit)
1332              {
1333                  $output .= $temp.$this->crlf;
1334                  $temp = '';
1335              }
1336  
1337              // Add the character to our temporary line
1338              $temp .= $char;
1339          }
1340  
1341          $str = $output.$temp;
1342  
1343          // wrap each line with the shebang, charset, and transfer encoding
1344          // the preceding space on successive lines is required for header "folding"
1345          $str = trim(preg_replace('/^(.*)$/m', ' =?'.$this->charset.'?Q?$1?=', $str));
1346  
1347          return $str;
1348      }
1349  
1350      // --------------------------------------------------------------------
1351  
1352      /**
1353       * Send Email
1354       *
1355       * @access    public
1356       * @return    bool
1357       */
1358  	public function send()
1359      {
1360          if ($this->_replyto_flag == FALSE)
1361          {
1362              $this->reply_to($this->_headers['From']);
1363          }
1364  
1365          if (( ! isset($this->_recipients) AND ! isset($this->_headers['To']))  AND
1366              ( ! isset($this->_bcc_array) AND ! isset($this->_headers['Bcc'])) AND
1367              ( ! isset($this->_headers['Cc'])))
1368          {
1369              $this->_set_error_message('lang:email_no_recipients');
1370              return FALSE;
1371          }
1372  
1373          $this->_build_headers();
1374  
1375          if ($this->bcc_batch_mode  AND  count($this->_bcc_array) > 0)
1376          {
1377              if (count($this->_bcc_array) > $this->bcc_batch_size)
1378                  return $this->batch_bcc_send();
1379          }
1380  
1381          $this->_build_message();
1382  
1383          if ( ! $this->_spool_email())
1384          {
1385              return FALSE;
1386          }
1387          else
1388          {
1389              return TRUE;
1390          }
1391      }
1392  
1393      // --------------------------------------------------------------------
1394  
1395      /**
1396       * Batch Bcc Send.  Sends groups of BCCs in batches
1397       *
1398       * @access    public
1399       * @return    bool
1400       */
1401  	public function batch_bcc_send()
1402      {
1403          $float = $this->bcc_batch_size -1;
1404  
1405          $set = "";
1406  
1407          $chunk = array();
1408  
1409          for ($i = 0; $i < count($this->_bcc_array); $i++)
1410          {
1411              if (isset($this->_bcc_array[$i]))
1412              {
1413                  $set .= ", ".$this->_bcc_array[$i];
1414              }
1415  
1416              if ($i == $float)
1417              {
1418                  $chunk[] = substr($set, 1);
1419                  $float = $float + $this->bcc_batch_size;
1420                  $set = "";
1421              }
1422  
1423              if ($i == count($this->_bcc_array)-1)
1424              {
1425                  $chunk[] = substr($set, 1);
1426              }
1427          }
1428  
1429          for ($i = 0; $i < count($chunk); $i++)
1430          {
1431              unset($this->_headers['Bcc']);
1432              unset($bcc);
1433  
1434              $bcc = $this->_str_to_array($chunk[$i]);
1435              $bcc = $this->clean_email($bcc);
1436  
1437              if ($this->protocol != 'smtp')
1438              {
1439                  $this->_set_header('Bcc', implode(", ", $bcc));
1440              }
1441              else
1442              {
1443                  $this->_bcc_array = $bcc;
1444              }
1445  
1446              $this->_build_message();
1447              $this->_spool_email();
1448          }
1449      }
1450  
1451      // --------------------------------------------------------------------
1452  
1453      /**
1454       * Unwrap special elements
1455       *
1456       * @access    protected
1457       * @return    void
1458       */
1459  	protected function _unwrap_specials()
1460      {
1461          $this->_finalbody = preg_replace_callback("/\{unwrap\}(.*?)\{\/unwrap\}/si", array($this, '_remove_nl_callback'), $this->_finalbody);
1462      }
1463  
1464      // --------------------------------------------------------------------
1465  
1466      /**
1467       * Strip line-breaks via callback
1468       *
1469       * @access    protected
1470       * @return    string
1471       */
1472  	protected function _remove_nl_callback($matches)
1473      {
1474          if (strpos($matches[1], "\r") !== FALSE OR strpos($matches[1], "\n") !== FALSE)
1475          {
1476              $matches[1] = str_replace(array("\r\n", "\r", "\n"), '', $matches[1]);
1477          }
1478  
1479          return $matches[1];
1480      }
1481  
1482      // --------------------------------------------------------------------
1483  
1484      /**
1485       * Spool mail to the mail server
1486       *
1487       * @access    protected
1488       * @return    bool
1489       */
1490  	protected function _spool_email()
1491      {
1492          $this->_unwrap_specials();
1493  
1494          switch ($this->_get_protocol())
1495          {
1496              case 'mail'    :
1497  
1498                      if ( ! $this->_send_with_mail())
1499                      {
1500                          $this->_set_error_message('lang:email_send_failure_phpmail');
1501                          return FALSE;
1502                      }
1503              break;
1504              case 'sendmail'    :
1505  
1506                      if ( ! $this->_send_with_sendmail())
1507                      {
1508                          $this->_set_error_message('lang:email_send_failure_sendmail');
1509                          return FALSE;
1510                      }
1511              break;
1512              case 'smtp'    :
1513  
1514                      if ( ! $this->_send_with_smtp())
1515                      {
1516                          $this->_set_error_message('lang:email_send_failure_smtp');
1517                          return FALSE;
1518                      }
1519              break;
1520  
1521          }
1522  
1523          $this->_set_error_message('lang:email_sent', $this->_get_protocol());
1524          return TRUE;
1525      }
1526  
1527      // --------------------------------------------------------------------
1528  
1529      /**
1530       * Send using mail()
1531       *
1532       * @access    protected
1533       * @return    bool
1534       */
1535  	protected function _send_with_mail()
1536      {
1537          if ($this->_safe_mode == TRUE)
1538          {
1539              if ( ! mail($this->_recipients, $this->_subject, $this->_finalbody, $this->_header_str))
1540              {
1541                  return FALSE;
1542              }
1543              else
1544              {
1545                  return TRUE;
1546              }
1547          }
1548          else
1549          {
1550              // most documentation of sendmail using the "-f" flag lacks a space after it, however
1551              // we've encountered servers that seem to require it to be in place.
1552  
1553              if ( ! mail($this->_recipients, $this->_subject, $this->_finalbody, $this->_header_str, "-f ".$this->clean_email($this->_headers['From'])))
1554              {
1555                  return FALSE;
1556              }
1557              else
1558              {
1559                  return TRUE;
1560              }
1561          }
1562      }
1563  
1564      // --------------------------------------------------------------------
1565  
1566      /**
1567       * Send using Sendmail
1568       *
1569       * @access    protected
1570       * @return    bool
1571       */
1572  	protected function _send_with_sendmail()
1573      {
1574          $fp = @popen($this->mailpath . " -oi -f ".$this->clean_email($this->_headers['From'])." -t", 'w');
1575  
1576          if ($fp === FALSE OR $fp === NULL)
1577          {
1578              // server probably has popen disabled, so nothing we can do to get a verbose error.
1579              return FALSE;
1580          }
1581  
1582          fputs($fp, $this->_header_str);
1583          fputs($fp, $this->_finalbody);
1584  
1585          $status = pclose($fp);
1586  
1587          if (version_compare(PHP_VERSION, '4.2.3') == -1)
1588          {
1589              $status = $status >> 8 & 0xFF;
1590          }
1591  
1592          if ($status != 0)
1593          {
1594              $this->_set_error_message('lang:email_exit_status', $status);
1595              $this->_set_error_message('lang:email_no_socket');
1596              return FALSE;
1597          }
1598  
1599          return TRUE;
1600      }
1601  
1602      // --------------------------------------------------------------------
1603  
1604      /**
1605       * Send using SMTP
1606       *
1607       * @access    protected
1608       * @return    bool
1609       */
1610  	protected function _send_with_smtp()
1611      {
1612          if ($this->smtp_host == '')
1613          {
1614              $this->_set_error_message('lang:email_no_hostname');
1615              return FALSE;
1616          }
1617  
1618          $this->_smtp_connect();
1619          $this->_smtp_authenticate();
1620  
1621          $this->_send_command('from', $this->clean_email($this->_headers['From']));
1622  
1623          foreach ($this->_recipients as $val)
1624          {
1625              $this->_send_command('to', $val);
1626          }
1627  
1628          if (count($this->_cc_array) > 0)
1629          {
1630              foreach ($this->_cc_array as $val)
1631              {
1632                  if ($val != "")
1633                  {
1634                      $this->_send_command('to', $val);
1635                  }
1636              }
1637          }
1638  
1639          if (count($this->_bcc_array) > 0)
1640          {
1641              foreach ($this->_bcc_array as $val)
1642              {
1643                  if ($val != "")
1644                  {
1645                      $this->_send_command('to', $val);
1646                  }
1647              }
1648          }
1649  
1650          $this->_send_command('data');
1651  
1652          // perform dot transformation on any lines that begin with a dot
1653          $this->_send_data($this->_header_str . preg_replace('/^\./m', '..$1', $this->_finalbody));
1654  
1655          $this->_send_data('.');
1656  
1657          $reply = $this->_get_smtp_data();
1658  
1659          $this->_set_error_message($reply);
1660  
1661          if (strncmp($reply, '250', 3) != 0)
1662          {
1663              $this->_set_error_message('lang:email_smtp_error', $reply);
1664              return FALSE;
1665          }
1666  
1667          $this->_send_command('quit');
1668          return TRUE;
1669      }
1670  
1671      // --------------------------------------------------------------------
1672  
1673      /**
1674       * SMTP Connect
1675       *
1676       * @access    protected
1677       * @param    string
1678       * @return    string
1679       */
1680  	protected function _smtp_connect()
1681      {
1682          $ssl = NULL;
1683          if ($this->smtp_crypto == 'ssl')
1684              $ssl = 'ssl://';
1685          $this->_smtp_connect = fsockopen($ssl.$this->smtp_host,
1686                                          $this->smtp_port,
1687                                          $errno,
1688                                          $errstr,
1689                                          $this->smtp_timeout);
1690  
1691          if ( ! is_resource($this->_smtp_connect))
1692          {
1693              $this->_set_error_message('lang:email_smtp_error', $errno." ".$errstr);
1694              return FALSE;
1695          }
1696  
1697          $this->_set_error_message($this->_get_smtp_data());
1698  
1699          if ($this->smtp_crypto == 'tls')
1700          {
1701              $this->_send_command('hello');
1702              $this->_send_command('starttls');
1703              stream_socket_enable_crypto($this->_smtp_connect, TRUE, STREAM_CRYPTO_METHOD_TLS_CLIENT);
1704          }
1705  
1706          return $this->_send_command('hello');
1707      }
1708  
1709      // --------------------------------------------------------------------
1710  
1711      /**
1712       * Send SMTP command
1713       *
1714       * @access    protected
1715       * @param    string
1716       * @param    string
1717       * @return    string
1718       */
1719  	protected function _send_command($cmd, $data = '')
1720      {
1721          switch ($cmd)
1722          {
1723              case 'hello' :
1724  
1725                      if ($this->_smtp_auth OR $this->_get_encoding() == '8bit')
1726                          $this->_send_data('EHLO '.$this->_get_hostname());
1727                      else
1728                          $this->_send_data('HELO '.$this->_get_hostname());
1729  
1730                          $resp = 250;
1731              break;
1732              case 'starttls'    :
1733  
1734                          $this->_send_data('STARTTLS');
1735  
1736                          $resp = 220;
1737              break;
1738              case 'from' :
1739  
1740                          $this->_send_data('MAIL FROM:<'.$data.'>');
1741  
1742                          $resp = 250;
1743              break;
1744              case 'to'    :
1745  
1746                          $this->_send_data('RCPT TO:<'.$data.'>');
1747  
1748                          $resp = 250;
1749              break;
1750              case 'data'    :
1751  
1752                          $this->_send_data('DATA');
1753  
1754                          $resp = 354;
1755              break;
1756              case 'quit'    :
1757  
1758                          $this->_send_data('QUIT');
1759  
1760                          $resp = 221;
1761              break;
1762          }
1763  
1764          $reply = $this->_get_smtp_data();
1765  
1766          $this->_debug_msg[] = "<pre>".$cmd.": ".$reply."</pre>";
1767  
1768          if (substr($reply, 0, 3) != $resp)
1769          {
1770              $this->_set_error_message('lang:email_smtp_error', $reply);
1771              return FALSE;
1772          }
1773  
1774          if ($cmd == 'quit')
1775          {
1776              fclose($this->_smtp_connect);
1777          }
1778  
1779          return TRUE;
1780      }
1781  
1782      // --------------------------------------------------------------------
1783  
1784      /**
1785       *  SMTP Authenticate
1786       *
1787       * @access    protected
1788       * @return    bool
1789       */
1790  	protected function _smtp_authenticate()
1791      {
1792          if ( ! $this->_smtp_auth)
1793          {
1794              return TRUE;
1795          }
1796  
1797          if ($this->smtp_user == ""  AND  $this->smtp_pass == "")
1798          {
1799              $this->_set_error_message('lang:email_no_smtp_unpw');
1800              return FALSE;
1801          }
1802  
1803          $this->_send_data('AUTH LOGIN');
1804  
1805          $reply = $this->_get_smtp_data();
1806  
1807          if (strncmp($reply, '334', 3) != 0)
1808          {
1809              $this->_set_error_message('lang:email_failed_smtp_login', $reply);
1810              return FALSE;
1811          }
1812  
1813          $this->_send_data(base64_encode($this->smtp_user));
1814  
1815          $reply = $this->_get_smtp_data();
1816  
1817          if (strncmp($reply, '334', 3) != 0)
1818          {
1819              $this->_set_error_message('lang:email_smtp_auth_un', $reply);
1820              return FALSE;
1821          }
1822  
1823          $this->_send_data(base64_encode($this->smtp_pass));
1824  
1825          $reply = $this->_get_smtp_data();
1826  
1827          if (strncmp($reply, '235', 3) != 0)
1828          {
1829              $this->_set_error_message('lang:email_smtp_auth_pw', $reply);
1830              return FALSE;
1831          }
1832  
1833          return TRUE;
1834      }
1835  
1836      // --------------------------------------------------------------------
1837  
1838      /**
1839       * Send SMTP data
1840       *
1841       * @access    protected
1842       * @return    bool
1843       */
1844  	protected function _send_data($data)
1845      {
1846          if ( ! fwrite($this->_smtp_connect, $data . $this->newline))
1847          {
1848              $this->_set_error_message('lang:email_smtp_data_failure', $data);
1849              return FALSE;
1850          }
1851          else
1852          {
1853              return TRUE;
1854          }
1855      }
1856  
1857      // --------------------------------------------------------------------
1858  
1859      /**
1860       * Get SMTP data
1861       *
1862       * @access    protected
1863       * @return    string
1864       */
1865  	protected function _get_smtp_data()
1866      {
1867          $data = "";
1868  
1869          while ($str = fgets($this->_smtp_connect, 512))
1870          {
1871              $data .= $str;
1872  
1873              if (substr($str, 3, 1) == " ")
1874              {
1875                  break;
1876              }
1877          }
1878  
1879          return $data;
1880      }
1881  
1882      // --------------------------------------------------------------------
1883  
1884      /**
1885       * Get Hostname
1886       *
1887       * @access    protected
1888       * @return    string
1889       */
1890  	protected function _get_hostname()
1891      {
1892          return (isset($_SERVER['SERVER_NAME'])) ? $_SERVER['SERVER_NAME'] : 'localhost.localdomain';
1893      }
1894  
1895      // --------------------------------------------------------------------
1896  
1897      /**
1898       * Get IP
1899       *
1900       * @access    protected
1901       * @return    string
1902       */
1903  	protected function _get_ip()
1904      {
1905          if ($this->_IP !== FALSE)
1906          {
1907              return $this->_IP;
1908          }
1909  
1910          $cip = (isset($_SERVER['HTTP_CLIENT_IP']) AND $_SERVER['HTTP_CLIENT_IP'] != "") ? $_SERVER['HTTP_CLIENT_IP'] : FALSE;
1911          $rip = (isset($_SERVER['REMOTE_ADDR']) AND $_SERVER['REMOTE_ADDR'] != "") ? $_SERVER['REMOTE_ADDR'] : FALSE;
1912          $fip = (isset($_SERVER['HTTP_X_FORWARDED_FOR']) AND $_SERVER['HTTP_X_FORWARDED_FOR'] != "") ? $_SERVER['HTTP_X_FORWARDED_FOR'] : FALSE;
1913  
1914          if ($cip && $rip)    $this->_IP = $cip;
1915          elseif ($rip)        $this->_IP = $rip;
1916          elseif ($cip)        $this->_IP = $cip;
1917          elseif ($fip)        $this->_IP = $fip;
1918  
1919          if (strpos($this->_IP, ',') !== FALSE)
1920          {
1921              $x = explode(',', $this->_IP);
1922              $this->_IP = end($x);
1923          }
1924  
1925          if ( ! preg_match( "/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/", $this->_IP))
1926          {
1927              $this->_IP = '0.0.0.0';
1928          }
1929  
1930          unset($cip);
1931          unset($rip);
1932          unset($fip);
1933  
1934          return $this->_IP;
1935      }
1936  
1937      // --------------------------------------------------------------------
1938  
1939      /**
1940       * Get Debug Message
1941       *
1942       * @access    public
1943       * @return    string
1944       */
1945  	public function print_debugger()
1946      {
1947          $msg = '';
1948  
1949          if (count($this->_debug_msg) > 0)
1950          {
1951              foreach ($this->_debug_msg as $val)
1952              {
1953                  $msg .= $val;
1954              }
1955          }
1956  
1957          $msg .= "<pre>".htmlspecialchars($this->_header_str)."\n".htmlspecialchars($this->_subject)."\n".htmlspecialchars($this->_finalbody).'</pre>';
1958          return $msg;
1959      }
1960  
1961      // --------------------------------------------------------------------
1962  
1963      /**
1964       * Set Message
1965       *
1966       * @access    protected
1967       * @param    string
1968       * @return    string
1969       */
1970  	protected function _set_error_message($msg, $val = '')
1971      {
1972          $CI =& get_instance();
1973          $CI->lang->load('email');
1974  
1975          if (substr($msg, 0, 5) != 'lang:' || FALSE === ($line = $CI->lang->line(substr($msg, 5))))
1976          {
1977              $this->_debug_msg[] = str_replace('%s', $val, $msg)."<br />";
1978          }
1979          else
1980          {
1981              $this->_debug_msg[] = str_replace('%s', $val, $line)."<br />";
1982          }
1983      }
1984  
1985      // --------------------------------------------------------------------
1986  
1987      /**
1988       * Mime Types
1989       *
1990       * @access    protected
1991       * @param    string
1992       * @return    string
1993       */
1994  	protected function _mime_types($ext = "")
1995      {
1996          $mimes = array(    'hqx'    =>    'application/mac-binhex40',
1997                          'cpt'    =>    'application/mac-compactpro',
1998                          'doc'    =>    'application/msword',
1999                          'bin'    =>    'application/macbinary',
2000                          'dms'    =>    'application/octet-stream',
2001                          'lha'    =>    'application/octet-stream',
2002                          'lzh'    =>    'application/octet-stream',
2003                          'exe'    =>    'application/octet-stream',
2004                          'class'    =>    'application/octet-stream',
2005                          'psd'    =>    'application/octet-stream',
2006                          'so'    =>    'application/octet-stream',
2007                          'sea'    =>    'application/octet-stream',
2008                          'dll'    =>    'application/octet-stream',
2009                          'oda'    =>    'application/oda',
2010                          'pdf'    =>    'application/pdf',
2011                          'ai'    =>    'application/postscript',
2012                          'eps'    =>    'application/postscript',
2013                          'ps'    =>    'application/postscript',
2014                          'smi'    =>    'application/smil',
2015                          'smil'    =>    'application/smil',
2016                          'mif'    =>    'application/vnd.mif',
2017                          'xls'    =>    'application/vnd.ms-excel',
2018                          'ppt'    =>    'application/vnd.ms-powerpoint',
2019                          'wbxml'    =>    'application/vnd.wap.wbxml',
2020                          'wmlc'    =>    'application/vnd.wap.wmlc',
2021                          'dcr'    =>    'application/x-director',
2022                          'dir'    =>    'application/x-director',
2023                          'dxr'    =>    'application/x-director',
2024                          'dvi'    =>    'application/x-dvi',
2025                          'gtar'    =>    'application/x-gtar',
2026                          'php'    =>    'application/x-httpd-php',
2027                          'php4'    =>    'application/x-httpd-php',
2028                          'php3'    =>    'application/x-httpd-php',
2029                          'phtml'    =>    'application/x-httpd-php',
2030                          'phps'    =>    'application/x-httpd-php-source',
2031                          'js'    =>    'application/x-javascript',
2032                          'swf'    =>    'application/x-shockwave-flash',
2033                          'sit'    =>    'application/x-stuffit',
2034                          'tar'    =>    'application/x-tar',
2035                          'tgz'    =>    'application/x-tar',
2036                          'xhtml'    =>    'application/xhtml+xml',
2037                          'xht'    =>    'application/xhtml+xml',
2038                          'zip'    =>    'application/zip',
2039                          'mid'    =>    'audio/midi',
2040                          'midi'    =>    'audio/midi',
2041                          'mpga'    =>    'audio/mpeg',
2042                          'mp2'    =>    'audio/mpeg',
2043                          'mp3'    =>    'audio/mpeg',
2044                          'aif'    =>    'audio/x-aiff',
2045                          'aiff'    =>    'audio/x-aiff',
2046                          'aifc'    =>    'audio/x-aiff',
2047                          'ram'    =>    'audio/x-pn-realaudio',
2048                          'rm'    =>    'audio/x-pn-realaudio',
2049                          'rpm'    =>    'audio/x-pn-realaudio-plugin',
2050                          'ra'    =>    'audio/x-realaudio',
2051                          'rv'    =>    'video/vnd.rn-realvideo',
2052                          'wav'    =>    'audio/x-wav',
2053                          'bmp'    =>    'image/bmp',
2054                          'gif'    =>    'image/gif',
2055                          'jpeg'    =>    'image/jpeg',
2056                          'jpg'    =>    'image/jpeg',
2057                          'jpe'    =>    'image/jpeg',
2058                          'png'    =>    'image/png',
2059                          'tiff'    =>    'image/tiff',
2060                          'tif'    =>    'image/tiff',
2061                          'css'    =>    'text/css',
2062                          'html'    =>    'text/html',
2063                          'htm'    =>    'text/html',
2064                          'shtml'    =>    'text/html',
2065                          'txt'    =>    'text/plain',
2066                          'text'    =>    'text/plain',
2067                          'log'    =>    'text/plain',
2068                          'rtx'    =>    'text/richtext',
2069                          'rtf'    =>    'text/rtf',
2070                          'xml'    =>    'text/xml',
2071                          'xsl'    =>    'text/xml',
2072                          'mpeg'    =>    'video/mpeg',
2073                          'mpg'    =>    'video/mpeg',
2074                          'mpe'    =>    'video/mpeg',
2075                          'qt'    =>    'video/quicktime',
2076                          'mov'    =>    'video/quicktime',
2077                          'avi'    =>    'video/x-msvideo',
2078                          'movie'    =>    'video/x-sgi-movie',
2079                          'doc'    =>    'application/msword',
2080                          'word'    =>    'application/msword',
2081                          'xl'    =>    'application/excel',
2082                          'eml'    =>    'message/rfc822'
2083                      );
2084  
2085          return ( ! isset($mimes[strtolower($ext)])) ? "application/x-unknown-content-type" : $mimes[strtolower($ext)];
2086      }
2087  
2088  }
2089  // END CI_Email class
2090  
2091  /* End of file Email.php */
2092  /* Location: ./system/libraries/Email.php */

title

Description

title

Description

title

Description

title

title

Body