PageRenderTime 49ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 1ms

/system/libraries/Email.php

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