source: trunk/forum/includes/functions_messenger.php

Last change on this file was 702, checked in by george, 15 years ago
  • Upraveno: Aktualizace fóra.
File size: 39.3 KB
Line 
1<?php
2/**
3*
4* @package phpBB3
5* @version $Id$
6* @copyright (c) 2005 phpBB Group
7* @license http://opensource.org/licenses/gpl-license.php GNU Public License
8*
9*/
10
11/**
12* @ignore
13*/
14if (!defined('IN_PHPBB'))
15{
16 exit;
17}
18
19/**
20* Messenger
21* @package phpBB3
22*/
23class messenger
24{
25 var $vars, $msg, $extra_headers, $replyto, $from, $subject;
26 var $addresses = array();
27
28 var $mail_priority = MAIL_NORMAL_PRIORITY;
29 var $use_queue = true;
30
31 var $tpl_obj = NULL;
32 var $tpl_msg = array();
33 var $eol = "\n";
34
35 /**
36 * Constructor
37 */
38 function messenger($use_queue = true)
39 {
40 global $config;
41
42 $this->use_queue = (!$config['email_package_size']) ? false : $use_queue;
43 $this->subject = '';
44
45 // Determine EOL character (\n for UNIX, \r\n for Windows and \r for Mac)
46 $this->eol = (!defined('PHP_EOL')) ? (($eol = strtolower(substr(PHP_OS, 0, 3))) == 'win') ? "\r\n" : (($eol == 'mac') ? "\r" : "\n") : PHP_EOL;
47 $this->eol = (!$this->eol) ? "\n" : $this->eol;
48 }
49
50 /**
51 * Resets all the data (address, template file, etc etc) to default
52 */
53 function reset()
54 {
55 $this->addresses = $this->extra_headers = array();
56 $this->vars = $this->msg = $this->replyto = $this->from = '';
57 $this->mail_priority = MAIL_NORMAL_PRIORITY;
58 }
59
60 /**
61 * Sets an email address to send to
62 */
63 function to($address, $realname = '')
64 {
65 global $config;
66
67 if (!trim($address))
68 {
69 return;
70 }
71
72 $pos = isset($this->addresses['to']) ? sizeof($this->addresses['to']) : 0;
73
74 $this->addresses['to'][$pos]['email'] = trim($address);
75
76 // If empty sendmail_path on windows, PHP changes the to line
77 if (!$config['smtp_delivery'] && DIRECTORY_SEPARATOR == '\\')
78 {
79 $this->addresses['to'][$pos]['name'] = '';
80 }
81 else
82 {
83 $this->addresses['to'][$pos]['name'] = trim($realname);
84 }
85 }
86
87 /**
88 * Sets an cc address to send to
89 */
90 function cc($address, $realname = '')
91 {
92 if (!trim($address))
93 {
94 return;
95 }
96
97 $pos = isset($this->addresses['cc']) ? sizeof($this->addresses['cc']) : 0;
98 $this->addresses['cc'][$pos]['email'] = trim($address);
99 $this->addresses['cc'][$pos]['name'] = trim($realname);
100 }
101
102 /**
103 * Sets an bcc address to send to
104 */
105 function bcc($address, $realname = '')
106 {
107 if (!trim($address))
108 {
109 return;
110 }
111
112 $pos = isset($this->addresses['bcc']) ? sizeof($this->addresses['bcc']) : 0;
113 $this->addresses['bcc'][$pos]['email'] = trim($address);
114 $this->addresses['bcc'][$pos]['name'] = trim($realname);
115 }
116
117 /**
118 * Sets a im contact to send to
119 */
120 function im($address, $realname = '')
121 {
122 // IM-Addresses could be empty
123 if (!trim($address))
124 {
125 return;
126 }
127
128 $pos = isset($this->addresses['im']) ? sizeof($this->addresses['im']) : 0;
129 $this->addresses['im'][$pos]['uid'] = trim($address);
130 $this->addresses['im'][$pos]['name'] = trim($realname);
131 }
132
133 /**
134 * Set the reply to address
135 */
136 function replyto($address)
137 {
138 $this->replyto = trim($address);
139 }
140
141 /**
142 * Set the from address
143 */
144 function from($address)
145 {
146 $this->from = trim($address);
147 }
148
149 /**
150 * set up subject for mail
151 */
152 function subject($subject = '')
153 {
154 $this->subject = trim($subject);
155 }
156
157 /**
158 * set up extra mail headers
159 */
160 function headers($headers)
161 {
162 $this->extra_headers[] = trim($headers);
163 }
164
165 /**
166 * Set the email priority
167 */
168 function set_mail_priority($priority = MAIL_NORMAL_PRIORITY)
169 {
170 $this->mail_priority = $priority;
171 }
172
173 /**
174 * Set email template to use
175 */
176 function template($template_file, $template_lang = '', $template_path = '')
177 {
178 global $config, $phpbb_root_path, $user;
179
180 if (!trim($template_file))
181 {
182 trigger_error('No template file for emailing set.', E_USER_ERROR);
183 }
184
185 if (!trim($template_lang))
186 {
187 // fall back to board default language if the user's language is
188 // missing $template_file. If this does not exist either,
189 // $tpl->set_custom_template will do a trigger_error
190 $template_lang = basename($config['default_lang']);
191 }
192
193 // tpl_msg now holds a template object we can use to parse the template file
194 if (!isset($this->tpl_msg[$template_lang . $template_file]))
195 {
196 $this->tpl_msg[$template_lang . $template_file] = new template();
197 $tpl = &$this->tpl_msg[$template_lang . $template_file];
198
199 $fallback_template_path = false;
200
201 if (!$template_path)
202 {
203 $template_path = (!empty($user->lang_path)) ? $user->lang_path : $phpbb_root_path . 'language/';
204 $template_path .= $template_lang . '/email';
205
206 // we can only specify default language fallback when the path is not a custom one for which we
207 // do not know the default language alternative
208 if ($template_lang !== basename($config['default_lang']))
209 {
210 $fallback_template_path = (!empty($user->lang_path)) ? $user->lang_path : $phpbb_root_path . 'language/';
211 $fallback_template_path .= basename($config['default_lang']) . '/email';
212 }
213 }
214
215 $tpl->set_custom_template($template_path, $template_lang . '_email', $fallback_template_path);
216
217 $tpl->set_filenames(array(
218 'body' => $template_file . '.txt',
219 ));
220 }
221
222 $this->tpl_obj = &$this->tpl_msg[$template_lang . $template_file];
223 $this->vars = &$this->tpl_obj->_rootref;
224 $this->tpl_msg = '';
225
226 return true;
227 }
228
229 /**
230 * assign variables to email template
231 */
232 function assign_vars($vars)
233 {
234 if (!is_object($this->tpl_obj))
235 {
236 return;
237 }
238
239 $this->tpl_obj->assign_vars($vars);
240 }
241
242 function assign_block_vars($blockname, $vars)
243 {
244 if (!is_object($this->tpl_obj))
245 {
246 return;
247 }
248
249 $this->tpl_obj->assign_block_vars($blockname, $vars);
250 }
251
252 /**
253 * Send the mail out to the recipients set previously in var $this->addresses
254 */
255 function send($method = NOTIFY_EMAIL, $break = false)
256 {
257 global $config, $user;
258
259 // We add some standard variables we always use, no need to specify them always
260 if (!isset($this->vars['U_BOARD']))
261 {
262 $this->assign_vars(array(
263 'U_BOARD' => generate_board_url(),
264 ));
265 }
266
267 if (!isset($this->vars['EMAIL_SIG']))
268 {
269 $this->assign_vars(array(
270 'EMAIL_SIG' => str_replace('<br />', "\n", "-- \n" . htmlspecialchars_decode($config['board_email_sig'])),
271 ));
272 }
273
274 if (!isset($this->vars['SITENAME']))
275 {
276 $this->assign_vars(array(
277 'SITENAME' => htmlspecialchars_decode($config['sitename']),
278 ));
279 }
280
281 // Parse message through template
282 $this->msg = trim($this->tpl_obj->assign_display('body'));
283
284 // Because we use \n for newlines in the body message we need to fix line encoding errors for those admins who uploaded email template files in the wrong encoding
285 $this->msg = str_replace("\r\n", "\n", $this->msg);
286
287 // We now try and pull a subject from the email body ... if it exists,
288 // do this here because the subject may contain a variable
289 $drop_header = '';
290 $match = array();
291 if (preg_match('#^(Subject:(.*?))$#m', $this->msg, $match))
292 {
293 $this->subject = (trim($match[2]) != '') ? trim($match[2]) : (($this->subject != '') ? $this->subject : $user->lang['NO_EMAIL_SUBJECT']);
294 $drop_header .= '[\r\n]*?' . preg_quote($match[1], '#');
295 }
296 else
297 {
298 $this->subject = (($this->subject != '') ? $this->subject : $user->lang['NO_EMAIL_SUBJECT']);
299 }
300
301 if ($drop_header)
302 {
303 $this->msg = trim(preg_replace('#' . $drop_header . '#s', '', $this->msg));
304 }
305
306 if ($break)
307 {
308 return true;
309 }
310
311 switch ($method)
312 {
313 case NOTIFY_EMAIL:
314 $result = $this->msg_email();
315 break;
316
317 case NOTIFY_IM:
318 $result = $this->msg_jabber();
319 break;
320
321 case NOTIFY_BOTH:
322 $result = $this->msg_email();
323 $this->msg_jabber();
324 break;
325 }
326
327 $this->reset();
328 return $result;
329 }
330
331 /**
332 * Add error message to log
333 */
334 function error($type, $msg)
335 {
336 global $user, $phpEx, $phpbb_root_path, $config;
337
338 // Session doesn't exist, create it
339 if (!isset($user->session_id) || $user->session_id === '')
340 {
341 $user->session_begin();
342 }
343
344 $calling_page = (!empty($_SERVER['PHP_SELF'])) ? $_SERVER['PHP_SELF'] : $_ENV['PHP_SELF'];
345
346 $message = '';
347 switch ($type)
348 {
349 case 'EMAIL':
350 $message = '<strong>EMAIL/' . (($config['smtp_delivery']) ? 'SMTP' : 'PHP/' . $config['email_function_name'] . '()') . '</strong>';
351 break;
352
353 default:
354 $message = "<strong>$type</strong>";
355 break;
356 }
357
358 $message .= '<br /><em>' . htmlspecialchars($calling_page) . '</em><br /><br />' . $msg . '<br />';
359 add_log('critical', 'LOG_ERROR_' . $type, $message);
360 }
361
362 /**
363 * Save to queue
364 */
365 function save_queue()
366 {
367 global $config;
368
369 if ($config['email_package_size'] && $this->use_queue && !empty($this->queue))
370 {
371 $this->queue->save();
372 return;
373 }
374 }
375
376 /**
377 * Return email header
378 */
379 function build_header($to, $cc, $bcc)
380 {
381 global $config;
382
383 // We could use keys here, but we won't do this for 3.0.x to retain backwards compatibility
384 $headers = array();
385
386 $headers[] = 'From: ' . $this->from;
387
388 if ($cc)
389 {
390 $headers[] = 'Cc: ' . $cc;
391 }
392
393 if ($bcc)
394 {
395 $headers[] = 'Bcc: ' . $bcc;
396 }
397
398 $headers[] = 'Reply-To: ' . $this->replyto;
399 $headers[] = 'Return-Path: <' . $config['board_email'] . '>';
400 $headers[] = 'Sender: <' . $config['board_email'] . '>';
401 $headers[] = 'MIME-Version: 1.0';
402 $headers[] = 'Message-ID: <' . md5(unique_id(time())) . '@' . $config['server_name'] . '>';
403 $headers[] = 'Date: ' . date('r', time());
404 $headers[] = 'Content-Type: text/plain; charset=UTF-8'; // format=flowed
405 $headers[] = 'Content-Transfer-Encoding: 8bit'; // 7bit
406
407 $headers[] = 'X-Priority: ' . $this->mail_priority;
408 $headers[] = 'X-MSMail-Priority: ' . (($this->mail_priority == MAIL_LOW_PRIORITY) ? 'Low' : (($this->mail_priority == MAIL_NORMAL_PRIORITY) ? 'Normal' : 'High'));
409 $headers[] = 'X-Mailer: phpBB3';
410 $headers[] = 'X-MimeOLE: phpBB3';
411 $headers[] = 'X-phpBB-Origin: phpbb://' . str_replace(array('http://', 'https://'), array('', ''), generate_board_url());
412
413 if (sizeof($this->extra_headers))
414 {
415 $headers = array_merge($headers, $this->extra_headers);
416 }
417
418 return $headers;
419 }
420
421 /**
422 * Send out emails
423 */
424 function msg_email()
425 {
426 global $config, $user;
427
428 if (empty($config['email_enable']))
429 {
430 return false;
431 }
432
433 // Addresses to send to?
434 if (empty($this->addresses) || (empty($this->addresses['to']) && empty($this->addresses['cc']) && empty($this->addresses['bcc'])))
435 {
436 // Send was successful. ;)
437 return true;
438 }
439
440 $use_queue = false;
441 if ($config['email_package_size'] && $this->use_queue)
442 {
443 if (empty($this->queue))
444 {
445 $this->queue = new queue();
446 $this->queue->init('email', $config['email_package_size']);
447 }
448 $use_queue = true;
449 }
450
451 if (empty($this->replyto))
452 {
453 $this->replyto = '<' . $config['board_contact'] . '>';
454 }
455
456 if (empty($this->from))
457 {
458 $this->from = '<' . $config['board_contact'] . '>';
459 }
460
461 $encode_eol = ($config['smtp_delivery']) ? "\r\n" : $this->eol;
462
463 // Build to, cc and bcc strings
464 $to = $cc = $bcc = '';
465 foreach ($this->addresses as $type => $address_ary)
466 {
467 if ($type == 'im')
468 {
469 continue;
470 }
471
472 foreach ($address_ary as $which_ary)
473 {
474 $$type .= (($$type != '') ? ', ' : '') . (($which_ary['name'] != '') ? mail_encode($which_ary['name'], $encode_eol) . ' <' . $which_ary['email'] . '>' : $which_ary['email']);
475 }
476 }
477
478 // Build header
479 $headers = $this->build_header($to, $cc, $bcc);
480
481 // Send message ...
482 if (!$use_queue)
483 {
484 $mail_to = ($to == '') ? 'undisclosed-recipients:;' : $to;
485 $err_msg = '';
486
487 if ($config['smtp_delivery'])
488 {
489 $result = smtpmail($this->addresses, mail_encode($this->subject), wordwrap(utf8_wordwrap($this->msg), 997, "\n", true), $err_msg, $headers);
490 }
491 else
492 {
493 $result = phpbb_mail($mail_to, $this->subject, $this->msg, $headers, $this->eol, $err_msg);
494 }
495
496 if (!$result)
497 {
498 $this->error('EMAIL', $err_msg);
499 return false;
500 }
501 }
502 else
503 {
504 $this->queue->put('email', array(
505 'to' => $to,
506 'addresses' => $this->addresses,
507 'subject' => $this->subject,
508 'msg' => $this->msg,
509 'headers' => $headers)
510 );
511 }
512
513 return true;
514 }
515
516 /**
517 * Send jabber message out
518 */
519 function msg_jabber()
520 {
521 global $config, $db, $user, $phpbb_root_path, $phpEx;
522
523 if (empty($config['jab_enable']) || empty($config['jab_host']) || empty($config['jab_username']) || empty($config['jab_password']))
524 {
525 return false;
526 }
527
528 if (empty($this->addresses['im']))
529 {
530 // Send was successful. ;)
531 return true;
532 }
533
534 $use_queue = false;
535 if ($config['jab_package_size'] && $this->use_queue)
536 {
537 if (empty($this->queue))
538 {
539 $this->queue = new queue();
540 $this->queue->init('jabber', $config['jab_package_size']);
541 }
542 $use_queue = true;
543 }
544
545 $addresses = array();
546 foreach ($this->addresses['im'] as $type => $uid_ary)
547 {
548 $addresses[] = $uid_ary['uid'];
549 }
550 $addresses = array_unique($addresses);
551
552 if (!$use_queue)
553 {
554 include_once($phpbb_root_path . 'includes/functions_jabber.' . $phpEx);
555 $this->jabber = new jabber($config['jab_host'], $config['jab_port'], $config['jab_username'], $config['jab_password'], $config['jab_use_ssl']);
556
557 if (!$this->jabber->connect())
558 {
559 $this->error('JABBER', $user->lang['ERR_JAB_CONNECT'] . '<br />' . $this->jabber->get_log());
560 return false;
561 }
562
563 if (!$this->jabber->login())
564 {
565 $this->error('JABBER', $user->lang['ERR_JAB_AUTH'] . '<br />' . $this->jabber->get_log());
566 return false;
567 }
568
569 foreach ($addresses as $address)
570 {
571 $this->jabber->send_message($address, $this->msg, $this->subject);
572 }
573
574 $this->jabber->disconnect();
575 }
576 else
577 {
578 $this->queue->put('jabber', array(
579 'addresses' => $addresses,
580 'subject' => $this->subject,
581 'msg' => $this->msg)
582 );
583 }
584 unset($addresses);
585 return true;
586 }
587}
588
589/**
590* handling email and jabber queue
591* @package phpBB3
592*/
593class queue
594{
595 var $data = array();
596 var $queue_data = array();
597 var $package_size = 0;
598 var $cache_file = '';
599 var $eol = "\n";
600
601 /**
602 * constructor
603 */
604 function queue()
605 {
606 global $phpEx, $phpbb_root_path;
607
608 $this->data = array();
609 $this->cache_file = "{$phpbb_root_path}cache/queue.$phpEx";
610
611 // Determine EOL character (\n for UNIX, \r\n for Windows and \r for Mac)
612 $this->eol = (!defined('PHP_EOL')) ? (($eol = strtolower(substr(PHP_OS, 0, 3))) == 'win') ? "\r\n" : (($eol == 'mac') ? "\r" : "\n") : PHP_EOL;
613 $this->eol = (!$this->eol) ? "\n" : $this->eol;
614 }
615
616 /**
617 * Init a queue object
618 */
619 function init($object, $package_size)
620 {
621 $this->data[$object] = array();
622 $this->data[$object]['package_size'] = $package_size;
623 $this->data[$object]['data'] = array();
624 }
625
626 /**
627 * Put object in queue
628 */
629 function put($object, $scope)
630 {
631 $this->data[$object]['data'][] = $scope;
632 }
633
634 /**
635 * Process queue
636 * Using lock file
637 */
638 function process()
639 {
640 global $db, $config, $phpEx, $phpbb_root_path, $user;
641
642 set_config('last_queue_run', time(), true);
643
644 // Delete stale lock file
645 if (file_exists($this->cache_file . '.lock') && !file_exists($this->cache_file))
646 {
647 @unlink($this->cache_file . '.lock');
648 return;
649 }
650
651 if (!file_exists($this->cache_file) || (file_exists($this->cache_file . '.lock') && filemtime($this->cache_file) > time() - $config['queue_interval']))
652 {
653 return;
654 }
655
656 $fp = @fopen($this->cache_file . '.lock', 'wb');
657 fclose($fp);
658 @chmod($this->cache_file . '.lock', 0777);
659
660 include($this->cache_file);
661
662 foreach ($this->queue_data as $object => $data_ary)
663 {
664 @set_time_limit(0);
665
666 if (!isset($data_ary['package_size']))
667 {
668 $data_ary['package_size'] = 0;
669 }
670
671 $package_size = $data_ary['package_size'];
672 $num_items = (!$package_size || sizeof($data_ary['data']) < $package_size) ? sizeof($data_ary['data']) : $package_size;
673
674 // If the amount of emails to be sent is way more than package_size than we need to increase it to prevent backlogs...
675 if (sizeof($data_ary['data']) > $package_size * 2.5)
676 {
677 $num_items = sizeof($data_ary['data']);
678 }
679
680 switch ($object)
681 {
682 case 'email':
683 // Delete the email queued objects if mailing is disabled
684 if (!$config['email_enable'])
685 {
686 unset($this->queue_data['email']);
687 continue 2;
688 }
689 break;
690
691 case 'jabber':
692 if (!$config['jab_enable'])
693 {
694 unset($this->queue_data['jabber']);
695 continue 2;
696 }
697
698 include_once($phpbb_root_path . 'includes/functions_jabber.' . $phpEx);
699 $this->jabber = new jabber($config['jab_host'], $config['jab_port'], $config['jab_username'], $config['jab_password'], $config['jab_use_ssl']);
700
701 if (!$this->jabber->connect())
702 {
703 messenger::error('JABBER', $user->lang['ERR_JAB_CONNECT']);
704 continue 2;
705 }
706
707 if (!$this->jabber->login())
708 {
709 messenger::error('JABBER', $user->lang['ERR_JAB_AUTH']);
710 continue 2;
711 }
712
713 break;
714
715 default:
716 return;
717 }
718
719 for ($i = 0; $i < $num_items; $i++)
720 {
721 // Make variables available...
722 extract(array_shift($this->queue_data[$object]['data']));
723
724 switch ($object)
725 {
726 case 'email':
727 $err_msg = '';
728 $to = (!$to) ? 'undisclosed-recipients:;' : $to;
729
730 if ($config['smtp_delivery'])
731 {
732 $result = smtpmail($addresses, mail_encode($subject), wordwrap(utf8_wordwrap($msg), 997, "\n", true), $err_msg, $headers);
733 }
734 else
735 {
736 $result = phpbb_mail($to, $subject, $msg, $headers, $this->eol, $err_msg);
737 }
738
739 if (!$result)
740 {
741 @unlink($this->cache_file . '.lock');
742
743 messenger::error('EMAIL', $err_msg);
744 continue 2;
745 }
746 break;
747
748 case 'jabber':
749 foreach ($addresses as $address)
750 {
751 if ($this->jabber->send_message($address, $msg, $subject) === false)
752 {
753 messenger::error('JABBER', $this->jabber->get_log());
754 continue 3;
755 }
756 }
757 break;
758 }
759 }
760
761 // No more data for this object? Unset it
762 if (!sizeof($this->queue_data[$object]['data']))
763 {
764 unset($this->queue_data[$object]);
765 }
766
767 // Post-object processing
768 switch ($object)
769 {
770 case 'jabber':
771 // Hang about a couple of secs to ensure the messages are
772 // handled, then disconnect
773 $this->jabber->disconnect();
774 break;
775 }
776 }
777
778 if (!sizeof($this->queue_data))
779 {
780 @unlink($this->cache_file);
781 }
782 else
783 {
784 if ($fp = @fopen($this->cache_file, 'wb'))
785 {
786 @flock($fp, LOCK_EX);
787 fwrite($fp, "<?php\nif (!defined('IN_PHPBB')) exit;\n\$this->queue_data = unserialize(" . var_export(serialize($this->queue_data), true) . ");\n\n?>");
788 @flock($fp, LOCK_UN);
789 fclose($fp);
790
791 phpbb_chmod($this->cache_file, CHMOD_READ | CHMOD_WRITE);
792 }
793 }
794
795 @unlink($this->cache_file . '.lock');
796 }
797
798 /**
799 * Save queue
800 */
801 function save()
802 {
803 if (!sizeof($this->data))
804 {
805 return;
806 }
807
808 if (file_exists($this->cache_file))
809 {
810 include($this->cache_file);
811
812 foreach ($this->queue_data as $object => $data_ary)
813 {
814 if (isset($this->data[$object]) && sizeof($this->data[$object]))
815 {
816 $this->data[$object]['data'] = array_merge($data_ary['data'], $this->data[$object]['data']);
817 }
818 else
819 {
820 $this->data[$object]['data'] = $data_ary['data'];
821 }
822 }
823 }
824
825 if ($fp = @fopen($this->cache_file, 'w'))
826 {
827 @flock($fp, LOCK_EX);
828 fwrite($fp, "<?php\nif (!defined('IN_PHPBB')) exit;\n\$this->queue_data = unserialize(" . var_export(serialize($this->data), true) . ");\n\n?>");
829 @flock($fp, LOCK_UN);
830 fclose($fp);
831
832 phpbb_chmod($this->cache_file, CHMOD_READ | CHMOD_WRITE);
833 }
834 }
835}
836
837/**
838* Replacement or substitute for PHP's mail command
839*/
840function smtpmail($addresses, $subject, $message, &$err_msg, $headers = false)
841{
842 global $config, $user;
843
844 // Fix any bare linefeeds in the message to make it RFC821 Compliant.
845 $message = preg_replace("#(?<!\r)\n#si", "\r\n", $message);
846
847 if ($headers !== false)
848 {
849 if (!is_array($headers))
850 {
851 // Make sure there are no bare linefeeds in the headers
852 $headers = preg_replace('#(?<!\r)\n#si', "\n", $headers);
853 $headers = explode("\n", $headers);
854 }
855
856 // Ok this is rather confusing all things considered,
857 // but we have to grab bcc and cc headers and treat them differently
858 // Something we really didn't take into consideration originally
859 $headers_used = array();
860
861 foreach ($headers as $header)
862 {
863 if (strpos(strtolower($header), 'cc:') === 0 || strpos(strtolower($header), 'bcc:') === 0)
864 {
865 continue;
866 }
867 $headers_used[] = trim($header);
868 }
869
870 $headers = chop(implode("\r\n", $headers_used));
871 }
872
873 if (trim($subject) == '')
874 {
875 $err_msg = (isset($user->lang['NO_EMAIL_SUBJECT'])) ? $user->lang['NO_EMAIL_SUBJECT'] : 'No email subject specified';
876 return false;
877 }
878
879 if (trim($message) == '')
880 {
881 $err_msg = (isset($user->lang['NO_EMAIL_MESSAGE'])) ? $user->lang['NO_EMAIL_MESSAGE'] : 'Email message was blank';
882 return false;
883 }
884
885 $mail_rcpt = $mail_to = $mail_cc = array();
886
887 // Build correct addresses for RCPT TO command and the client side display (TO, CC)
888 if (isset($addresses['to']) && sizeof($addresses['to']))
889 {
890 foreach ($addresses['to'] as $which_ary)
891 {
892 $mail_to[] = ($which_ary['name'] != '') ? mail_encode(trim($which_ary['name'])) . ' <' . trim($which_ary['email']) . '>' : '<' . trim($which_ary['email']) . '>';
893 $mail_rcpt['to'][] = '<' . trim($which_ary['email']) . '>';
894 }
895 }
896
897 if (isset($addresses['bcc']) && sizeof($addresses['bcc']))
898 {
899 foreach ($addresses['bcc'] as $which_ary)
900 {
901 $mail_rcpt['bcc'][] = '<' . trim($which_ary['email']) . '>';
902 }
903 }
904
905 if (isset($addresses['cc']) && sizeof($addresses['cc']))
906 {
907 foreach ($addresses['cc'] as $which_ary)
908 {
909 $mail_cc[] = ($which_ary['name'] != '') ? mail_encode(trim($which_ary['name'])) . ' <' . trim($which_ary['email']) . '>' : '<' . trim($which_ary['email']) . '>';
910 $mail_rcpt['cc'][] = '<' . trim($which_ary['email']) . '>';
911 }
912 }
913
914 $smtp = new smtp_class();
915
916 $errno = 0;
917 $errstr = '';
918
919 $smtp->add_backtrace('Connecting to ' . $config['smtp_host'] . ':' . $config['smtp_port']);
920
921 // Ok we have error checked as much as we can to this point let's get on it already.
922 ob_start();
923 $smtp->socket = fsockopen($config['smtp_host'], $config['smtp_port'], $errno, $errstr, 20);
924 $error_contents = ob_get_clean();
925
926 if (!$smtp->socket)
927 {
928 if ($errstr)
929 {
930 $errstr = utf8_convert_message($errstr);
931 }
932
933 $err_msg = (isset($user->lang['NO_CONNECT_TO_SMTP_HOST'])) ? sprintf($user->lang['NO_CONNECT_TO_SMTP_HOST'], $errno, $errstr) : "Could not connect to smtp host : $errno : $errstr";
934 $err_msg .= ($error_contents) ? '<br /><br />' . htmlspecialchars($error_contents) : '';
935 return false;
936 }
937
938 // Wait for reply
939 if ($err_msg = $smtp->server_parse('220', __LINE__))
940 {
941 $smtp->close_session($err_msg);
942 return false;
943 }
944
945 // Let me in. This function handles the complete authentication process
946 if ($err_msg = $smtp->log_into_server($config['smtp_host'], $config['smtp_username'], $config['smtp_password'], $config['smtp_auth_method']))
947 {
948 $smtp->close_session($err_msg);
949 return false;
950 }
951
952 // From this point onward most server response codes should be 250
953 // Specify who the mail is from....
954 $smtp->server_send('MAIL FROM:<' . $config['board_email'] . '>');
955 if ($err_msg = $smtp->server_parse('250', __LINE__))
956 {
957 $smtp->close_session($err_msg);
958 return false;
959 }
960
961 // Specify each user to send to and build to header.
962 $to_header = implode(', ', $mail_to);
963 $cc_header = implode(', ', $mail_cc);
964
965 // Now tell the MTA to send the Message to the following people... [TO, BCC, CC]
966 $rcpt = false;
967 foreach ($mail_rcpt as $type => $mail_to_addresses)
968 {
969 foreach ($mail_to_addresses as $mail_to_address)
970 {
971 // Add an additional bit of error checking to the To field.
972 if (preg_match('#[^ ]+\@[^ ]+#', $mail_to_address))
973 {
974 $smtp->server_send("RCPT TO:$mail_to_address");
975 if ($err_msg = $smtp->server_parse('250', __LINE__))
976 {
977 // We continue... if users are not resolved we do not care
978 if ($smtp->numeric_response_code != 550)
979 {
980 $smtp->close_session($err_msg);
981 return false;
982 }
983 }
984 else
985 {
986 $rcpt = true;
987 }
988 }
989 }
990 }
991
992 // We try to send messages even if a few people do not seem to have valid email addresses, but if no one has, we have to exit here.
993 if (!$rcpt)
994 {
995 $user->session_begin();
996 $err_msg .= '<br /><br />';
997 $err_msg .= (isset($user->lang['INVALID_EMAIL_LOG'])) ? sprintf($user->lang['INVALID_EMAIL_LOG'], htmlspecialchars($mail_to_address)) : '<strong>' . htmlspecialchars($mail_to_address) . '</strong> possibly an invalid email address?';
998 $smtp->close_session($err_msg);
999 return false;
1000 }
1001
1002 // Ok now we tell the server we are ready to start sending data
1003 $smtp->server_send('DATA');
1004
1005 // This is the last response code we look for until the end of the message.
1006 if ($err_msg = $smtp->server_parse('354', __LINE__))
1007 {
1008 $smtp->close_session($err_msg);
1009 return false;
1010 }
1011
1012 // Send the Subject Line...
1013 $smtp->server_send("Subject: $subject");
1014
1015 // Now the To Header.
1016 $to_header = ($to_header == '') ? 'undisclosed-recipients:;' : $to_header;
1017 $smtp->server_send("To: $to_header");
1018
1019 // Now the CC Header.
1020 if ($cc_header != '')
1021 {
1022 $smtp->server_send("CC: $cc_header");
1023 }
1024
1025 // Now any custom headers....
1026 if ($headers !== false)
1027 {
1028 $smtp->server_send("$headers\r\n");
1029 }
1030
1031 // Ok now we are ready for the message...
1032 $smtp->server_send($message);
1033
1034 // Ok the all the ingredients are mixed in let's cook this puppy...
1035 $smtp->server_send('.');
1036 if ($err_msg = $smtp->server_parse('250', __LINE__))
1037 {
1038 $smtp->close_session($err_msg);
1039 return false;
1040 }
1041
1042 // Now tell the server we are done and close the socket...
1043 $smtp->server_send('QUIT');
1044 $smtp->close_session($err_msg);
1045
1046 return true;
1047}
1048
1049/**
1050* SMTP Class
1051* Auth Mechanisms originally taken from the AUTH Modules found within the PHP Extension and Application Repository (PEAR)
1052* See docs/AUTHORS for more details
1053* @package phpBB3
1054*/
1055class smtp_class
1056{
1057 var $server_response = '';
1058 var $socket = 0;
1059 var $responses = array();
1060 var $commands = array();
1061 var $numeric_response_code = 0;
1062
1063 var $backtrace = false;
1064 var $backtrace_log = array();
1065
1066 function smtp_class()
1067 {
1068 // Always create a backtrace for admins to identify SMTP problems
1069 $this->backtrace = true;
1070 $this->backtrace_log = array();
1071 }
1072
1073 /**
1074 * Add backtrace message for debugging
1075 */
1076 function add_backtrace($message)
1077 {
1078 if ($this->backtrace)
1079 {
1080 $this->backtrace_log[] = utf8_htmlspecialchars($message);
1081 }
1082 }
1083
1084 /**
1085 * Send command to smtp server
1086 */
1087 function server_send($command, $private_info = false)
1088 {
1089 fputs($this->socket, $command . "\r\n");
1090
1091 (!$private_info) ? $this->add_backtrace("# $command") : $this->add_backtrace('# Omitting sensitive information');
1092
1093 // We could put additional code here
1094 }
1095
1096 /**
1097 * We use the line to give the support people an indication at which command the error occurred
1098 */
1099 function server_parse($response, $line)
1100 {
1101 global $user;
1102
1103 $this->server_response = '';
1104 $this->responses = array();
1105 $this->numeric_response_code = 0;
1106
1107 while (substr($this->server_response, 3, 1) != ' ')
1108 {
1109 if (!($this->server_response = fgets($this->socket, 256)))
1110 {
1111 return (isset($user->lang['NO_EMAIL_RESPONSE_CODE'])) ? $user->lang['NO_EMAIL_RESPONSE_CODE'] : 'Could not get mail server response codes';
1112 }
1113 $this->responses[] = substr(rtrim($this->server_response), 4);
1114 $this->numeric_response_code = (int) substr($this->server_response, 0, 3);
1115
1116 $this->add_backtrace("LINE: $line <- {$this->server_response}");
1117 }
1118
1119 if (!(substr($this->server_response, 0, 3) == $response))
1120 {
1121 $this->numeric_response_code = (int) substr($this->server_response, 0, 3);
1122 return (isset($user->lang['EMAIL_SMTP_ERROR_RESPONSE'])) ? sprintf($user->lang['EMAIL_SMTP_ERROR_RESPONSE'], $line, $this->server_response) : "Ran into problems sending Mail at <strong>Line $line</strong>. Response: $this->server_response";
1123 }
1124
1125 return 0;
1126 }
1127
1128 /**
1129 * Close session
1130 */
1131 function close_session(&$err_msg)
1132 {
1133 fclose($this->socket);
1134
1135 if ($this->backtrace)
1136 {
1137 $message = '<h1>Backtrace</h1><p>' . implode('<br />', $this->backtrace_log) . '</p>';
1138 $err_msg .= $message;
1139 }
1140 }
1141
1142 /**
1143 * Log into server and get possible auth codes if neccessary
1144 */
1145 function log_into_server($hostname, $username, $password, $default_auth_method)
1146 {
1147 global $user;
1148
1149 $err_msg = '';
1150
1151 // Here we try to determine the *real* hostname (reverse DNS entry preferrably)
1152 $local_host = $user->host;
1153
1154 if (function_exists('php_uname'))
1155 {
1156 $local_host = php_uname('n');
1157
1158 // Able to resolve name to IP
1159 if (($addr = @gethostbyname($local_host)) !== $local_host)
1160 {
1161 // Able to resolve IP back to name
1162 if (($name = @gethostbyaddr($addr)) !== $addr)
1163 {
1164 $local_host = $name;
1165 }
1166 }
1167 }
1168
1169 // If we are authenticating through pop-before-smtp, we
1170 // have to login ones before we get authenticated
1171 // NOTE: on some configurations the time between an update of the auth database takes so
1172 // long that the first email send does not work. This is not a biggie on a live board (only
1173 // the install mail will most likely fail) - but on a dynamic ip connection this might produce
1174 // severe problems and is not fixable!
1175 if ($default_auth_method == 'POP-BEFORE-SMTP' && $username && $password)
1176 {
1177 global $config;
1178
1179 $errno = 0;
1180 $errstr = '';
1181
1182 $this->server_send("QUIT");
1183 fclose($this->socket);
1184
1185 $result = $this->pop_before_smtp($hostname, $username, $password);
1186 $username = $password = $default_auth_method = '';
1187
1188 // We need to close the previous session, else the server is not
1189 // able to get our ip for matching...
1190 if (!$this->socket = @fsockopen($config['smtp_host'], $config['smtp_port'], $errno, $errstr, 10))
1191 {
1192 if ($errstr)
1193 {
1194 $errstr = utf8_convert_message($errstr);
1195 }
1196
1197 $err_msg = (isset($user->lang['NO_CONNECT_TO_SMTP_HOST'])) ? sprintf($user->lang['NO_CONNECT_TO_SMTP_HOST'], $errno, $errstr) : "Could not connect to smtp host : $errno : $errstr";
1198 return $err_msg;
1199 }
1200
1201 // Wait for reply
1202 if ($err_msg = $this->server_parse('220', __LINE__))
1203 {
1204 $this->close_session($err_msg);
1205 return $err_msg;
1206 }
1207 }
1208
1209 // Try EHLO first
1210 $this->server_send("EHLO {$local_host}");
1211 if ($err_msg = $this->server_parse('250', __LINE__))
1212 {
1213 // a 503 response code means that we're already authenticated
1214 if ($this->numeric_response_code == 503)
1215 {
1216 return false;
1217 }
1218
1219 // If EHLO fails, we try HELO
1220 $this->server_send("HELO {$local_host}");
1221 if ($err_msg = $this->server_parse('250', __LINE__))
1222 {
1223 return ($this->numeric_response_code == 503) ? false : $err_msg;
1224 }
1225 }
1226
1227 foreach ($this->responses as $response)
1228 {
1229 $response = explode(' ', $response);
1230 $response_code = $response[0];
1231 unset($response[0]);
1232 $this->commands[$response_code] = implode(' ', $response);
1233 }
1234
1235 // If we are not authenticated yet, something might be wrong if no username and passwd passed
1236 if (!$username || !$password)
1237 {
1238 return false;
1239 }
1240
1241 if (!isset($this->commands['AUTH']))
1242 {
1243 return (isset($user->lang['SMTP_NO_AUTH_SUPPORT'])) ? $user->lang['SMTP_NO_AUTH_SUPPORT'] : 'SMTP server does not support authentication';
1244 }
1245
1246 // Get best authentication method
1247 $available_methods = explode(' ', $this->commands['AUTH']);
1248
1249 // Define the auth ordering if the default auth method was not found
1250 $auth_methods = array('PLAIN', 'LOGIN', 'CRAM-MD5', 'DIGEST-MD5');
1251 $method = '';
1252
1253 if (in_array($default_auth_method, $available_methods))
1254 {
1255 $method = $default_auth_method;
1256 }
1257 else
1258 {
1259 foreach ($auth_methods as $_method)
1260 {
1261 if (in_array($_method, $available_methods))
1262 {
1263 $method = $_method;
1264 break;
1265 }
1266 }
1267 }
1268
1269 if (!$method)
1270 {
1271 return (isset($user->lang['NO_SUPPORTED_AUTH_METHODS'])) ? $user->lang['NO_SUPPORTED_AUTH_METHODS'] : 'No supported authentication methods';
1272 }
1273
1274 $method = strtolower(str_replace('-', '_', $method));
1275 return $this->$method($username, $password);
1276 }
1277
1278 /**
1279 * Pop before smtp authentication
1280 */
1281 function pop_before_smtp($hostname, $username, $password)
1282 {
1283 global $user;
1284
1285 if (!$this->socket = @fsockopen($hostname, 110, $errno, $errstr, 10))
1286 {
1287 if ($errstr)
1288 {
1289 $errstr = utf8_convert_message($errstr);
1290 }
1291
1292 return (isset($user->lang['NO_CONNECT_TO_SMTP_HOST'])) ? sprintf($user->lang['NO_CONNECT_TO_SMTP_HOST'], $errno, $errstr) : "Could not connect to smtp host : $errno : $errstr";
1293 }
1294
1295 $this->server_send("USER $username", true);
1296 if ($err_msg = $this->server_parse('+OK', __LINE__))
1297 {
1298 return $err_msg;
1299 }
1300
1301 $this->server_send("PASS $password", true);
1302 if ($err_msg = $this->server_parse('+OK', __LINE__))
1303 {
1304 return $err_msg;
1305 }
1306
1307 $this->server_send('QUIT');
1308 fclose($this->socket);
1309
1310 return false;
1311 }
1312
1313 /**
1314 * Plain authentication method
1315 */
1316 function plain($username, $password)
1317 {
1318 $this->server_send('AUTH PLAIN');
1319 if ($err_msg = $this->server_parse('334', __LINE__))
1320 {
1321 return ($this->numeric_response_code == 503) ? false : $err_msg;
1322 }
1323
1324 $base64_method_plain = base64_encode("\0" . $username . "\0" . $password);
1325 $this->server_send($base64_method_plain, true);
1326 if ($err_msg = $this->server_parse('235', __LINE__))
1327 {
1328 return $err_msg;
1329 }
1330
1331 return false;
1332 }
1333
1334 /**
1335 * Login authentication method
1336 */
1337 function login($username, $password)
1338 {
1339 $this->server_send('AUTH LOGIN');
1340 if ($err_msg = $this->server_parse('334', __LINE__))
1341 {
1342 return ($this->numeric_response_code == 503) ? false : $err_msg;
1343 }
1344
1345 $this->server_send(base64_encode($username), true);
1346 if ($err_msg = $this->server_parse('334', __LINE__))
1347 {
1348 return $err_msg;
1349 }
1350
1351 $this->server_send(base64_encode($password), true);
1352 if ($err_msg = $this->server_parse('235', __LINE__))
1353 {
1354 return $err_msg;
1355 }
1356
1357 return false;
1358 }
1359
1360 /**
1361 * cram_md5 authentication method
1362 */
1363 function cram_md5($username, $password)
1364 {
1365 $this->server_send('AUTH CRAM-MD5');
1366 if ($err_msg = $this->server_parse('334', __LINE__))
1367 {
1368 return ($this->numeric_response_code == 503) ? false : $err_msg;
1369 }
1370
1371 $md5_challenge = base64_decode($this->responses[0]);
1372 $password = (strlen($password) > 64) ? pack('H32', md5($password)) : ((strlen($password) < 64) ? str_pad($password, 64, chr(0)) : $password);
1373 $md5_digest = md5((substr($password, 0, 64) ^ str_repeat(chr(0x5C), 64)) . (pack('H32', md5((substr($password, 0, 64) ^ str_repeat(chr(0x36), 64)) . $md5_challenge))));
1374
1375 $base64_method_cram_md5 = base64_encode($username . ' ' . $md5_digest);
1376
1377 $this->server_send($base64_method_cram_md5, true);
1378 if ($err_msg = $this->server_parse('235', __LINE__))
1379 {
1380 return $err_msg;
1381 }
1382
1383 return false;
1384 }
1385
1386 /**
1387 * digest_md5 authentication method
1388 * A real pain in the ***
1389 */
1390 function digest_md5($username, $password)
1391 {
1392 global $config, $user;
1393
1394 $this->server_send('AUTH DIGEST-MD5');
1395 if ($err_msg = $this->server_parse('334', __LINE__))
1396 {
1397 return ($this->numeric_response_code == 503) ? false : $err_msg;
1398 }
1399
1400 $md5_challenge = base64_decode($this->responses[0]);
1401
1402 // Parse the md5 challenge - from AUTH_SASL (PEAR)
1403 $tokens = array();
1404 while (preg_match('/^([a-z-]+)=("[^"]+(?<!\\\)"|[^,]+)/i', $md5_challenge, $matches))
1405 {
1406 // Ignore these as per rfc2831
1407 if ($matches[1] == 'opaque' || $matches[1] == 'domain')
1408 {
1409 $md5_challenge = substr($md5_challenge, strlen($matches[0]) + 1);
1410 continue;
1411 }
1412
1413 // Allowed multiple "realm" and "auth-param"
1414 if (!empty($tokens[$matches[1]]) && ($matches[1] == 'realm' || $matches[1] == 'auth-param'))
1415 {
1416 if (is_array($tokens[$matches[1]]))
1417 {
1418 $tokens[$matches[1]][] = preg_replace('/^"(.*)"$/', '\\1', $matches[2]);
1419 }
1420 else
1421 {
1422 $tokens[$matches[1]] = array($tokens[$matches[1]], preg_replace('/^"(.*)"$/', '\\1', $matches[2]));
1423 }
1424 }
1425 else if (!empty($tokens[$matches[1]])) // Any other multiple instance = failure
1426 {
1427 $tokens = array();
1428 break;
1429 }
1430 else
1431 {
1432 $tokens[$matches[1]] = preg_replace('/^"(.*)"$/', '\\1', $matches[2]);
1433 }
1434
1435 // Remove the just parsed directive from the challenge
1436 $md5_challenge = substr($md5_challenge, strlen($matches[0]) + 1);
1437 }
1438
1439 // Realm
1440 if (empty($tokens['realm']))
1441 {
1442 $tokens['realm'] = (function_exists('php_uname')) ? php_uname('n') : $user->host;
1443 }
1444
1445 // Maxbuf
1446 if (empty($tokens['maxbuf']))
1447 {
1448 $tokens['maxbuf'] = 65536;
1449 }
1450
1451 // Required: nonce, algorithm
1452 if (empty($tokens['nonce']) || empty($tokens['algorithm']))
1453 {
1454 $tokens = array();
1455 }
1456 $md5_challenge = $tokens;
1457
1458 if (!empty($md5_challenge))
1459 {
1460 $str = '';
1461 for ($i = 0; $i < 32; $i++)
1462 {
1463 $str .= chr(mt_rand(0, 255));
1464 }
1465 $cnonce = base64_encode($str);
1466
1467 $digest_uri = 'smtp/' . $config['smtp_host'];
1468
1469 $auth_1 = sprintf('%s:%s:%s', pack('H32', md5(sprintf('%s:%s:%s', $username, $md5_challenge['realm'], $password))), $md5_challenge['nonce'], $cnonce);
1470 $auth_2 = 'AUTHENTICATE:' . $digest_uri;
1471 $response_value = md5(sprintf('%s:%s:00000001:%s:auth:%s', md5($auth_1), $md5_challenge['nonce'], $cnonce, md5($auth_2)));
1472
1473 $input_string = sprintf('username="%s",realm="%s",nonce="%s",cnonce="%s",nc="00000001",qop=auth,digest-uri="%s",response=%s,%d', $username, $md5_challenge['realm'], $md5_challenge['nonce'], $cnonce, $digest_uri, $response_value, $md5_challenge['maxbuf']);
1474 }
1475 else
1476 {
1477 return (isset($user->lang['INVALID_DIGEST_CHALLENGE'])) ? $user->lang['INVALID_DIGEST_CHALLENGE'] : 'Invalid digest challenge';
1478 }
1479
1480 $base64_method_digest_md5 = base64_encode($input_string);
1481 $this->server_send($base64_method_digest_md5, true);
1482 if ($err_msg = $this->server_parse('334', __LINE__))
1483 {
1484 return $err_msg;
1485 }
1486
1487 $this->server_send(' ');
1488 if ($err_msg = $this->server_parse('235', __LINE__))
1489 {
1490 return $err_msg;
1491 }
1492
1493 return false;
1494 }
1495}
1496
1497/**
1498* Encodes the given string for proper display in UTF-8.
1499*
1500* This version is using base64 encoded data. The downside of this
1501* is if the mail client does not understand this encoding the user
1502* is basically doomed with an unreadable subject.
1503*
1504* Please note that this version fully supports RFC 2045 section 6.8.
1505*
1506* @param string $eol End of line we are using (optional to be backwards compatible)
1507*/
1508function mail_encode($str, $eol = "\r\n")
1509{
1510 // define start delimimter, end delimiter and spacer
1511 $start = "=?UTF-8?B?";
1512 $end = "?=";
1513 $delimiter = "$eol ";
1514
1515 // Maximum length is 75. $split_length *must* be a multiple of 4, but <= 75 - strlen($start . $delimiter . $end)!!!
1516 $split_length = 60;
1517 $encoded_str = base64_encode($str);
1518
1519 // If encoded string meets the limits, we just return with the correct data.
1520 if (strlen($encoded_str) <= $split_length)
1521 {
1522 return $start . $encoded_str . $end;
1523 }
1524
1525 // If there is only ASCII data, we just return what we want, correctly splitting the lines.
1526 if (strlen($str) === utf8_strlen($str))
1527 {
1528 return $start . implode($end . $delimiter . $start, str_split($encoded_str, $split_length)) . $end;
1529 }
1530
1531 // UTF-8 data, compose encoded lines
1532 $array = utf8_str_split($str);
1533 $str = '';
1534
1535 while (sizeof($array))
1536 {
1537 $text = '';
1538
1539 while (sizeof($array) && intval((strlen($text . $array[0]) + 2) / 3) << 2 <= $split_length)
1540 {
1541 $text .= array_shift($array);
1542 }
1543
1544 $str .= $start . base64_encode($text) . $end . $delimiter;
1545 }
1546
1547 return substr($str, 0, -strlen($delimiter));
1548}
1549
1550/**
1551* Wrapper for sending out emails with the PHP's mail function
1552*/
1553function phpbb_mail($to, $subject, $msg, $headers, $eol, &$err_msg)
1554{
1555 global $config;
1556
1557 // We use the EOL character for the OS here because the PHP mail function does not correctly transform line endings. On Windows SMTP is used (SMTP is \r\n), on UNIX a command is used...
1558 // Reference: http://bugs.php.net/bug.php?id=15841
1559 $headers = implode($eol, $headers);
1560
1561 ob_start();
1562 // On some PHP Versions mail() *may* fail if there are newlines within the subject.
1563 // Newlines are used as a delimiter for lines in mail_encode() according to RFC 2045 section 6.8.
1564 // Because PHP can't decide what is wanted we revert back to the non-RFC-compliant way of separating by one space (Use '' as parameter to mail_encode() results in SPACE used)
1565 $result = $config['email_function_name']($to, mail_encode($subject, ''), wordwrap(utf8_wordwrap($msg), 997, "\n", true), $headers);
1566 $err_msg = ob_get_clean();
1567
1568 return $result;
1569}
1570
1571?>
Note: See TracBrowser for help on using the repository browser.