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