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