source: sourcecode/system/libraries/Email.php @ 1

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