Subversion-Projekte lars-tiefland.codeigniter

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

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