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