PageRenderTime 207ms CodeModel.GetById 80ms app.highlight 94ms RepoModel.GetById 17ms app.codeStats 1ms

/system/libraries/Email.php

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