Advertisement
Guest User

Untitled

a guest
Jan 27th, 2014
80
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 48.88 KB | None | 0 0
  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      = "RobotCMS";
  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 <[email protected]>
  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>".$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 */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement