Verzeichnisstruktur phpBB-3.0.0
- Veröffentlicht
- 12.12.2007
So funktioniert es
|
Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück |
Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis. |
|
(Beispiel Datei-Icons)
|
Auf das Icon klicken um den Quellcode anzuzeigen |
functions_messenger.php
0001 <?php
0002 /**
0003 *
0004 * @package phpBB3
0005 * @version $Id$
0006 * @copyright (c) 2005 phpBB Group
0007 * @license http://opensource.org/licenses/gpl-license.php GNU Public License
0008 *
0009 */
0010
0011 /**
0012 * @ignore
0013 */
0014 if (!defined('IN_PHPBB'))
0015 {
0016 exit;
0017 }
0018
0019 /**
0020 * Messenger
0021 * @package phpBB3
0022 */
0023 class messenger
0024 {
0025 var $vars, $msg, $extra_headers, $replyto, $from, $subject;
0026 var $addresses = array();
0027
0028 var $mail_priority = MAIL_NORMAL_PRIORITY;
0029 var $use_queue = true;
0030 var $tpl_msg = array();
0031
0032 /**
0033 * Constructor
0034 */
0035 function messenger($use_queue = true)
0036 {
0037 global $config;
0038
0039 $this->use_queue = (!$config['email_package_size']) ? false : $use_queue;
0040 $this->subject = '';
0041 }
0042
0043 /**
0044 * Resets all the data (address, template file, etc etc) to default
0045 */
0046 function reset()
0047 {
0048 $this->addresses = $this->extra_headers = array();
0049 $this->vars = $this->msg = $this->replyto = $this->from = '';
0050 $this->mail_priority = MAIL_NORMAL_PRIORITY;
0051 }
0052
0053 /**
0054 * Sets an email address to send to
0055 */
0056 function to($address, $realname = '')
0057 {
0058 global $config;
0059
0060 $pos = isset($this->addresses['to']) ? sizeof($this->addresses['to']) : 0;
0061
0062 $this->addresses['to'][$pos]['email'] = trim($address);
0063
0064 // If empty sendmail_path on windows, PHP changes the to line
0065 if (!$config['smtp_delivery'] && DIRECTORY_SEPARATOR == '\\')
0066 {
0067 $this->addresses['to'][$pos]['name'] = '';
0068 }
0069 else
0070 {
0071 $this->addresses['to'][$pos]['name'] = trim($realname);
0072 }
0073 }
0074
0075 /**
0076 * Sets an cc address to send to
0077 */
0078 function cc($address, $realname = '')
0079 {
0080 $pos = isset($this->addresses['cc']) ? sizeof($this->addresses['cc']) : 0;
0081 $this->addresses['cc'][$pos]['email'] = trim($address);
0082 $this->addresses['cc'][$pos]['name'] = trim($realname);
0083 }
0084
0085 /**
0086 * Sets an bcc address to send to
0087 */
0088 function bcc($address, $realname = '')
0089 {
0090 $pos = isset($this->addresses['bcc']) ? sizeof($this->addresses['bcc']) : 0;
0091 $this->addresses['bcc'][$pos]['email'] = trim($address);
0092 $this->addresses['bcc'][$pos]['name'] = trim($realname);
0093 }
0094
0095 /**
0096 * Sets a im contact to send to
0097 */
0098 function im($address, $realname = '')
0099 {
0100 $pos = isset($this->addresses['im']) ? sizeof($this->addresses['im']) : 0;
0101 $this->addresses['im'][$pos]['uid'] = trim($address);
0102 $this->addresses['im'][$pos]['name'] = trim($realname);
0103 }
0104
0105 /**
0106 * Set the reply to address
0107 */
0108 function replyto($address)
0109 {
0110 $this->replyto = trim($address);
0111 }
0112
0113 /**
0114 * Set the from address
0115 */
0116 function from($address)
0117 {
0118 $this->from = trim($address);
0119 }
0120
0121 /**
0122 * set up subject for mail
0123 */
0124 function subject($subject = '')
0125 {
0126 $this->subject = trim($subject);
0127 }
0128
0129 /**
0130 * set up extra mail headers
0131 */
0132 function headers($headers)
0133 {
0134 $this->extra_headers[] = trim($headers);
0135 }
0136
0137 /**
0138 * Set the email priority
0139 */
0140 function set_mail_priority($priority = MAIL_NORMAL_PRIORITY)
0141 {
0142 $this->mail_priority = $priority;
0143 }
0144
0145 /**
0146 * Set email template to use
0147 */
0148 function template($template_file, $template_lang = '')
0149 {
0150 global $config, $phpbb_root_path;
0151
0152 if (!trim($template_file))
0153 {
0154 trigger_error('No template file set', E_USER_ERROR);
0155 }
0156
0157 if (!trim($template_lang))
0158 {
0159 $template_lang = basename($config['default_lang']);
0160 }
0161
0162 if (empty($this->tpl_msg[$template_lang . $template_file]))
0163 {
0164 $tpl_file = "{$phpbb_root_path}language/$template_lang/email/$template_file.txt";
0165
0166 if (!file_exists($tpl_file))
0167 {
0168 trigger_error("Could not find email template file [ $tpl_file ]", E_USER_ERROR);
0169 }
0170
0171 if (($data = @file_get_contents($tpl_file)) === false)
0172 {
0173 trigger_error("Failed opening template file [ $tpl_file ]", E_USER_ERROR);
0174 }
0175
0176 $this->tpl_msg[$template_lang . $template_file] = $data;
0177 }
0178
0179 $this->msg = $this->tpl_msg[$template_lang . $template_file];
0180
0181 return true;
0182 }
0183
0184 /**
0185 * assign variables to email template
0186 */
0187 function assign_vars($vars)
0188 {
0189 $this->vars = (empty($this->vars)) ? $vars : $this->vars + $vars;
0190 }
0191
0192 /**
0193 * Send the mail out to the recipients set previously in var $this->addresses
0194 */
0195 function send($method = NOTIFY_EMAIL, $break = false)
0196 {
0197 global $config, $user;
0198
0199 // We add some standard variables we always use, no need to specify them always
0200 $this->vars['U_BOARD'] = (!isset($this->vars['U_BOARD'])) ? generate_board_url() : $this->vars['U_BOARD'];
0201 $this->vars['EMAIL_SIG'] = (!isset($this->vars['EMAIL_SIG'])) ? str_replace('<br />', "\n", "-- \n" . htmlspecialchars_decode($config['board_email_sig'])) : $this->vars['EMAIL_SIG'];
0202 $this->vars['SITENAME'] = (!isset($this->vars['SITENAME'])) ? htmlspecialchars_decode($config['sitename']) : $this->vars['SITENAME'];
0203
0204 // Escape all quotes, else the eval will fail.
0205 $this->msg = str_replace ("'", "\'", $this->msg);
0206 $this->msg = preg_replace('#\{([a-z0-9\-_]*?)\}#is', "' . ((isset(\$this->vars['\\1'])) ? \$this->vars['\\1'] : '') . '", $this->msg);
0207
0208 eval("\$this->msg = '$this->msg';");
0209
0210 // We now try and pull a subject from the email body ... if it exists,
0211 // do this here because the subject may contain a variable
0212 $drop_header = '';
0213 $match = array();
0214 if (preg_match('#^(Subject:(.*?))$#m', $this->msg, $match))
0215 {
0216 $this->subject = (trim($match[2]) != '') ? trim($match[2]) : (($this->subject != '') ? $this->subject : $user->lang['NO_EMAIL_SUBJECT']);
0217 $drop_header .= '[\r\n]*?' . preg_quote($match[1], '#');
0218 }
0219 else
0220 {
0221 $this->subject = (($this->subject != '') ? $this->subject : $user->lang['NO_EMAIL_SUBJECT']);
0222 }
0223
0224 if ($drop_header)
0225 {
0226 $this->msg = trim(preg_replace('#' . $drop_header . '#s', '', $this->msg));
0227 }
0228
0229 if ($break)
0230 {
0231 return true;
0232 }
0233
0234 switch ($method)
0235 {
0236 case NOTIFY_EMAIL:
0237 $result = $this->msg_email();
0238 break;
0239
0240 case NOTIFY_IM:
0241 $result = $this->msg_jabber();
0242 break;
0243
0244 case NOTIFY_BOTH:
0245 $result = $this->msg_email();
0246 $this->msg_jabber();
0247 break;
0248 }
0249
0250 $this->reset();
0251 return $result;
0252 }
0253
0254 /**
0255 * Add error message to log
0256 */
0257 function error($type, $msg)
0258 {
0259 global $user, $phpEx, $phpbb_root_path, $config;
0260
0261 // Session doesn't exist, create it
0262 if (!isset($user->session_id) || $user->session_id === '')
0263 {
0264 $user->session_begin();
0265 }
0266
0267 $calling_page = (!empty($_SERVER['PHP_SELF'])) ? $_SERVER['PHP_SELF'] : $_ENV['PHP_SELF'];
0268
0269 $message = '';
0270 switch ($type)
0271 {
0272 case 'EMAIL':
0273 $message = '<strong>EMAIL/' . (($config['smtp_delivery']) ? 'SMTP' : 'PHP/' . $config['email_function_name'] . '()') . '</strong>';
0274 break;
0275
0276 default:
0277 $message = "<strong>$type</strong>";
0278 break;
0279 }
0280
0281 $message .= '<br /><em>' . htmlspecialchars($calling_page) . '</em><br /><br />' . $msg . '<br />';
0282 add_log('critical', 'LOG_ERROR_' . $type, $message);
0283 }
0284
0285 /**
0286 * Save to queue
0287 */
0288 function save_queue()
0289 {
0290 global $config;
0291
0292 if ($config['email_package_size'] && $this->use_queue && !empty($this->queue))
0293 {
0294 $this->queue->save();
0295 return;
0296 }
0297 }
0298
0299 /**
0300 * Return email header
0301 */
0302 function build_header($to, $cc, $bcc)
0303 {
0304 global $config;
0305
0306 $headers = array();
0307
0308 $headers[] = 'From: ' . $this->from;
0309
0310 if ($cc)
0311 {
0312 $headers[] = 'Cc: ' . $cc;
0313 }
0314
0315 if ($bcc)
0316 {
0317 $headers[] = 'Bcc: ' . $bcc;
0318 }
0319
0320 $headers[] = 'Reply-To: ' . $this->replyto;
0321 $headers[] = 'Return-Path: <' . $config['board_email'] . '>';
0322 $headers[] = 'Sender: <' . $config['board_email'] . '>';
0323 $headers[] = 'MIME-Version: 1.0';
0324 $headers[] = 'Message-ID: <' . md5(unique_id(time())) . '@' . $config['server_name'] . '>';
0325 $headers[] = 'Date: ' . date('r', time());
0326 $headers[] = 'Content-Type: text/plain; charset=UTF-8'; // format=flowed
0327 $headers[] = 'Content-Transfer-Encoding: 8bit'; // 7bit
0328
0329 $headers[] = 'X-Priority: ' . $this->mail_priority;
0330 $headers[] = 'X-MSMail-Priority: ' . (($this->mail_priority == MAIL_LOW_PRIORITY) ? 'Low' : (($this->mail_priority == MAIL_NORMAL_PRIORITY) ? 'Normal' : 'High'));
0331 $headers[] = 'X-Mailer: PhpBB3';
0332 $headers[] = 'X-MimeOLE: phpBB3';
0333 $headers[] = 'X-phpBB-Origin: phpbb://' . str_replace(array('http://', 'https://'), array('', ''), generate_board_url());
0334
0335 // We use \n here instead of \r\n because our smtp mailer is adjusting it to \r\n automatically, whereby the php mail function only works
0336 // if using \n.
0337
0338 if (sizeof($this->extra_headers))
0339 {
0340 $headers[] = implode("\n", $this->extra_headers);
0341 }
0342
0343 return implode("\n", $headers);
0344 }
0345
0346 /**
0347 * Send out emails
0348 */
0349 function msg_email()
0350 {
0351 global $config, $user;
0352
0353 if (empty($config['email_enable']))
0354 {
0355 return false;
0356 }
0357
0358 $use_queue = false;
0359 if ($config['email_package_size'] && $this->use_queue)
0360 {
0361 if (empty($this->queue))
0362 {
0363 $this->queue = new queue();
0364 $this->queue->init('email', $config['email_package_size']);
0365 }
0366 $use_queue = true;
0367 }
0368
0369 if (empty($this->replyto))
0370 {
0371 $this->replyto = '<' . $config['board_contact'] . '>';
0372 }
0373
0374 if (empty($this->from))
0375 {
0376 $this->from = '<' . $config['board_contact'] . '>';
0377 }
0378
0379 // Build to, cc and bcc strings
0380 $to = $cc = $bcc = '';
0381 foreach ($this->addresses as $type => $address_ary)
0382 {
0383 if ($type == 'im')
0384 {
0385 continue;
0386 }
0387
0388 foreach ($address_ary as $which_ary)
0389 {
0390 $$type .= (($$type != '') ? ', ' : '') . (($which_ary['name'] != '') ? '"' . mail_encode($which_ary['name']) . '" <' . $which_ary['email'] . '>' : $which_ary['email']);
0391 }
0392 }
0393
0394 // Build header
0395 $headers = $this->build_header($to, $cc, $bcc);
0396
0397 // Send message ...
0398 if (!$use_queue)
0399 {
0400 $mail_to = ($to == '') ? 'undisclosed-recipients:;' : $to;
0401 $err_msg = '';
0402
0403 if ($config['smtp_delivery'])
0404 {
0405 $result = smtpmail($this->addresses, mail_encode($this->subject), wordwrap(utf8_wordwrap($this->msg), 997, "\n", true), $err_msg, $headers);
0406 }
0407 else
0408 {
0409 ob_start();
0410 $result = $config['email_function_name']($mail_to, mail_encode($this->subject), wordwrap(utf8_wordwrap($this->msg), 997, "\n", true), $headers);
0411 $err_msg = ob_get_clean();
0412 }
0413
0414 if (!$result)
0415 {
0416 $this->error('EMAIL', $err_msg);
0417 return false;
0418 }
0419 }
0420 else
0421 {
0422 $this->queue->put('email', array(
0423 'to' => $to,
0424 'addresses' => $this->addresses,
0425 'subject' => $this->subject,
0426 'msg' => $this->msg,
0427 'headers' => $headers)
0428 );
0429 }
0430
0431 return true;
0432 }
0433
0434 /**
0435 * Send jabber message out
0436 */
0437 function msg_jabber()
0438 {
0439 global $config, $db, $user, $phpbb_root_path, $phpEx;
0440
0441 if (empty($config['jab_enable']) || empty($config['jab_host']) || empty($config['jab_username']) || empty($config['jab_password']))
0442 {
0443 return false;
0444 }
0445
0446 $use_queue = false;
0447 if ($config['jab_package_size'] && $this->use_queue)
0448 {
0449 if (empty($this->queue))
0450 {
0451 $this->queue = new queue();
0452 $this->queue->init('jabber', $config['jab_package_size']);
0453 }
0454 $use_queue = true;
0455 }
0456
0457 $addresses = array();
0458 foreach ($this->addresses['im'] as $type => $uid_ary)
0459 {
0460 $addresses[] = $uid_ary['uid'];
0461 }
0462 $addresses = array_unique($addresses);
0463
0464 if (!$use_queue)
0465 {
0466 include_once($phpbb_root_path . 'includes/functions_jabber.' . $phpEx);
0467 $this->jabber = new jabber($config['jab_host'], $config['jab_port'], $config['jab_username'], $config['jab_password'], $config['jab_use_ssl']);
0468
0469 if (!$this->jabber->connect())
0470 {
0471 $this->error('JABBER', $user->lang['ERR_JAB_CONNECT'] . '<br />' . $this->jabber->get_log());
0472 return false;
0473 }
0474
0475 if (!$this->jabber->login())
0476 {
0477 $this->error('JABBER', $user->lang['ERR_JAB_AUTH'] . '<br />' . $this->jabber->get_log());
0478 return false;
0479 }
0480
0481 foreach ($addresses as $address)
0482 {
0483 $this->jabber->send_message($address, $this->msg, $this->subject);
0484 }
0485
0486 $this->jabber->disconnect();
0487 }
0488 else
0489 {
0490 $this->queue->put('jabber', array(
0491 'addresses' => $addresses,
0492 'subject' => $this->subject,
0493 'msg' => $this->msg)
0494 );
0495 }
0496 unset($addresses);
0497 return true;
0498 }
0499 }
0500
0501 /**
0502 * handling email and jabber queue
0503 * @package phpBB3
0504 */
0505 class queue
0506 {
0507 var $data = array();
0508 var $queue_data = array();
0509 var $package_size = 0;
0510 var $cache_file = '';
0511
0512 /**
0513 * constructor
0514 */
0515 function queue()
0516 {
0517 global $phpEx, $phpbb_root_path;
0518
0519 $this->data = array();
0520 $this->cache_file = "{$phpbb_root_path}cache/queue.$phpEx";
0521 }
0522
0523 /**
0524 * Init a queue object
0525 */
0526 function init($object, $package_size)
0527 {
0528 $this->data[$object] = array();
0529 $this->data[$object]['package_size'] = $package_size;
0530 $this->data[$object]['data'] = array();
0531 }
0532
0533 /**
0534 * Put object in queue
0535 */
0536 function put($object, $scope)
0537 {
0538 $this->data[$object]['data'][] = $scope;
0539 }
0540
0541 /**
0542 * Process queue
0543 * Using lock file
0544 */
0545 function process()
0546 {
0547 global $db, $config, $phpEx, $phpbb_root_path, $user;
0548
0549 set_config('last_queue_run', time(), true);
0550
0551 // Delete stale lock file
0552 if (file_exists($this->cache_file . '.lock') && !file_exists($this->cache_file))
0553 {
0554 @unlink($this->cache_file . '.lock');
0555 return;
0556 }
0557
0558 if (!file_exists($this->cache_file) || (file_exists($this->cache_file . '.lock') && filemtime($this->cache_file) > time() - $config['queue_interval']))
0559 {
0560 return;
0561 }
0562
0563 $fp = @fopen($this->cache_file . '.lock', 'wb');
0564 fclose($fp);
0565 @chmod($this->cache_file . '.lock', 0666);
0566
0567 include($this->cache_file);
0568
0569 foreach ($this->queue_data as $object => $data_ary)
0570 {
0571 @set_time_limit(0);
0572
0573 if (!isset($data_ary['package_size']))
0574 {
0575 $data_ary['package_size'] = 0;
0576 }
0577
0578 $package_size = $data_ary['package_size'];
0579 $num_items = (!$package_size || sizeof($data_ary['data']) < $package_size) ? sizeof($data_ary['data']) : $package_size;
0580
0581 // If the amount of emails to be sent is way more than package_size than we need to increase it to prevent backlogs...
0582 if (sizeof($data_ary['data']) > $package_size * 2.5)
0583 {
0584 $num_items = sizeof($data_ary['data']);
0585 }
0586
0587 switch ($object)
0588 {
0589 case 'email':
0590 // Delete the email queued objects if mailing is disabled
0591 if (!$config['email_enable'])
0592 {
0593 unset($this->queue_data['email']);
0594 continue 2;
0595 }
0596 break;
0597
0598 case 'jabber':
0599 if (!$config['jab_enable'])
0600 {
0601 unset($this->queue_data['jabber']);
0602 continue 2;
0603 }
0604
0605 include_once($phpbb_root_path . 'includes/functions_jabber.' . $phpEx);
0606 $this->jabber = new jabber($config['jab_host'], $config['jab_port'], $config['jab_username'], $config['jab_password'], $config['jab_use_ssl']);
0607
0608 if (!$this->jabber->connect())
0609 {
0610 messenger::error('JABBER', $user->lang['ERR_JAB_CONNECT']);
0611 continue 2;
0612 }
0613
0614 if (!$this->jabber->login())
0615 {
0616 messenger::error('JABBER', $user->lang['ERR_JAB_AUTH']);
0617 continue 2;
0618 }
0619
0620 break;
0621
0622 default:
0623 return;
0624 }
0625
0626 for ($i = 0; $i < $num_items; $i++)
0627 {
0628 // Make variables available...
0629 extract(array_shift($this->queue_data[$object]['data']));
0630
0631 switch ($object)
0632 {
0633 case 'email':
0634 $err_msg = '';
0635 $to = (!$to) ? 'undisclosed-recipients:;' : $to;
0636
0637 if ($config['smtp_delivery'])
0638 {
0639 $result = smtpmail($addresses, mail_encode($subject), wordwrap(utf8_wordwrap($msg), 997, "\n", true), $err_msg, $headers);
0640 }
0641 else
0642 {
0643 ob_start();
0644 $result = $config['email_function_name']($to, mail_encode($subject), wordwrap(utf8_wordwrap($msg), 997, "\n", true), $headers);
0645 $err_msg = ob_get_clean();
0646 }
0647
0648 if (!$result)
0649 {
0650 @unlink($this->cache_file . '.lock');
0651
0652 messenger::error('EMAIL', $err_msg);
0653 continue 2;
0654 }
0655 break;
0656
0657 case 'jabber':
0658 foreach ($addresses as $address)
0659 {
0660 if ($this->jabber->send_message($address, $msg, $subject) === false)
0661 {
0662 messenger::error('JABBER', $this->jabber->get_log());
0663 continue 3;
0664 }
0665 }
0666 break;
0667 }
0668 }
0669
0670 // No more data for this object? Unset it
0671 if (!sizeof($this->queue_data[$object]['data']))
0672 {
0673 unset($this->queue_data[$object]);
0674 }
0675
0676 // Post-object processing
0677 switch ($object)
0678 {
0679 case 'jabber':
0680 // Hang about a couple of secs to ensure the messages are
0681 // handled, then disconnect
0682 $this->jabber->disconnect();
0683 break;
0684 }
0685 }
0686
0687 if (!sizeof($this->queue_data))
0688 {
0689 @unlink($this->cache_file);
0690 }
0691 else
0692 {
0693 if ($fp = @fopen($this->cache_file, 'w'))
0694 {
0695 @flock($fp, LOCK_EX);
0696 fwrite($fp, "<?php\n\$this->queue_data = " . var_export($this->queue_data, true) . ";\n?>");
0697 @flock($fp, LOCK_UN);
0698 fclose($fp);
0699
0700 @chmod($this->cache_file, 0666);
0701 }
0702 }
0703
0704 @unlink($this->cache_file . '.lock');
0705 }
0706
0707 /**
0708 * Save queue
0709 */
0710 function save()
0711 {
0712 if (!sizeof($this->data))
0713 {
0714 return;
0715 }
0716
0717 if (file_exists($this->cache_file))
0718 {
0719 include($this->cache_file);
0720
0721 foreach ($this->queue_data as $object => $data_ary)
0722 {
0723 if (isset($this->data[$object]) && sizeof($this->data[$object]))
0724 {
0725 $this->data[$object]['data'] = array_merge($data_ary['data'], $this->data[$object]['data']);
0726 }
0727 else
0728 {
0729 $this->data[$object]['data'] = $data_ary['data'];
0730 }
0731 }
0732 }
0733
0734 if ($fp = @fopen($this->cache_file, 'w'))
0735 {
0736 @flock($fp, LOCK_EX);
0737 fwrite($fp, "<?php\n\$this->queue_data = " . var_export($this->data, true) . ";\n?>");
0738 @flock($fp, LOCK_UN);
0739 fclose($fp);
0740
0741 @chmod($this->cache_file, 0666);
0742 }
0743 }
0744 }
0745
0746 /**
0747 * Replacement or substitute for PHP's mail command
0748 */
0749 function smtpmail($addresses, $subject, $message, &$err_msg, $headers = '')
0750 {
0751 global $config, $user;
0752
0753 // Fix any bare linefeeds in the message to make it RFC821 Compliant.
0754 $message = preg_replace("#(?<!\r)\n#si", "\r\n", $message);
0755
0756 if ($headers != '')
0757 {
0758 if (is_array($headers))
0759 {
0760 $headers = (sizeof($headers) > 1) ? join("\n", $headers) : $headers[0];
0761 }
0762 $headers = chop($headers);
0763
0764 // Make sure there are no bare linefeeds in the headers
0765 $headers = preg_replace('#(?<!\r)\n#si', "\r\n", $headers);
0766
0767 // Ok this is rather confusing all things considered,
0768 // but we have to grab bcc and cc headers and treat them differently
0769 // Something we really didn't take into consideration originally
0770 $header_array = explode("\r\n", $headers);
0771 $headers = '';
0772
0773 foreach ($header_array as $header)
0774 {
0775 if (strpos(strtolower($header), 'cc:') === 0 || strpos(strtolower($header), 'bcc:') === 0)
0776 {
0777 $header = '';
0778 }
0779 $headers .= ($header != '') ? $header . "\r\n" : '';
0780 }
0781
0782 $headers = chop($headers);
0783 }
0784
0785 if (trim($subject) == '')
0786 {
0787 $err_msg = (isset($user->lang['NO_EMAIL_SUBJECT'])) ? $user->lang['NO_EMAIL_SUBJECT'] : 'No email subject specified';
0788 return false;
0789 }
0790
0791 if (trim($message) == '')
0792 {
0793 $err_msg = (isset($user->lang['NO_EMAIL_MESSAGE'])) ? $user->lang['NO_EMAIL_MESSAGE'] : 'Email message was blank';
0794 return false;
0795 }
0796
0797 $mail_rcpt = $mail_to = $mail_cc = array();
0798
0799 // Build correct addresses for RCPT TO command and the client side display (TO, CC)
0800 if (isset($addresses['to']) && sizeof($addresses['to']))
0801 {
0802 foreach ($addresses['to'] as $which_ary)
0803 {
0804 $mail_to[] = ($which_ary['name'] != '') ? mail_encode(trim($which_ary['name'])) . ' <' . trim($which_ary['email']) . '>' : '<' . trim($which_ary['email']) . '>';
0805 $mail_rcpt['to'][] = '<' . trim($which_ary['email']) . '>';
0806 }
0807 }
0808
0809 if (isset($addresses['bcc']) && sizeof($addresses['bcc']))
0810 {
0811 foreach ($addresses['bcc'] as $which_ary)
0812 {
0813 $mail_rcpt['bcc'][] = '<' . trim($which_ary['email']) . '>';
0814 }
0815 }
0816
0817 if (isset($addresses['cc']) && sizeof($addresses['cc']))
0818 {
0819 foreach ($addresses['cc'] as $which_ary)
0820 {
0821 $mail_cc[] = ($which_ary['name'] != '') ? mail_encode(trim($which_ary['name'])) . ' <' . trim($which_ary['email']) . '>' : '<' . trim($which_ary['email']) . '>';
0822 $mail_rcpt['cc'][] = '<' . trim($which_ary['email']) . '>';
0823 }
0824 }
0825
0826 $smtp = new smtp_class();
0827
0828 $errno = 0;
0829 $errstr = '';
0830
0831 $smtp->add_backtrace('Connecting to ' . $config['smtp_host'] . ':' . $config['smtp_port']);
0832
0833 // Ok we have error checked as much as we can to this point let's get on it already.
0834 ob_start();
0835 $smtp->socket = fsockopen($config['smtp_host'], $config['smtp_port'], $errno, $errstr, 20);
0836 $error_contents = ob_get_clean();
0837
0838 if (!$smtp->socket)
0839 {
0840 if ($errstr)
0841 {
0842 $errstr = utf8_convert_message($errstr);
0843 }
0844
0845 $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";
0846 $err_msg .= ($error_contents) ? '<br /><br />' . htmlspecialchars($error_contents) : '';
0847 return false;
0848 }
0849
0850 // Wait for reply
0851 if ($err_msg = $smtp->server_parse('220', __LINE__))
0852 {
0853 $smtp->close_session($err_msg);
0854 return false;
0855 }
0856
0857 // Let me in. This function handles the complete authentication process
0858 if ($err_msg = $smtp->log_into_server($config['smtp_host'], $config['smtp_username'], $config['smtp_password'], $config['smtp_auth_method']))
0859 {
0860 $smtp->close_session($err_msg);
0861 return false;
0862 }
0863
0864 // From this point onward most server response codes should be 250
0865 // Specify who the mail is from....
0866 $smtp->server_send('MAIL FROM:<' . $config['board_email'] . '>');
0867 if ($err_msg = $smtp->server_parse('250', __LINE__))
0868 {
0869 $smtp->close_session($err_msg);
0870 return false;
0871 }
0872
0873 // Specify each user to send to and build to header.
0874 $to_header = implode(', ', $mail_to);
0875 $cc_header = implode(', ', $mail_cc);
0876
0877 // Now tell the MTA to send the Message to the following people... [TO, BCC, CC]
0878 $rcpt = false;
0879 foreach ($mail_rcpt as $type => $mail_to_addresses)
0880 {
0881 foreach ($mail_to_addresses as $mail_to_address)
0882 {
0883 // Add an additional bit of error checking to the To field.
0884 if (preg_match('#[^ ]+\@[^ ]+#', $mail_to_address))
0885 {
0886 $smtp->server_send("RCPT TO:$mail_to_address");
0887 if ($err_msg = $smtp->server_parse('250', __LINE__))
0888 {
0889 // We continue... if users are not resolved we do not care
0890 if ($smtp->numeric_response_code != 550)
0891 {
0892 $smtp->close_session($err_msg);
0893 return false;
0894 }
0895 }
0896 else
0897 {
0898 $rcpt = true;
0899 }
0900 }
0901 }
0902 }
0903
0904 // 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.
0905 if (!$rcpt)
0906 {
0907 $user->session_begin();
0908 $err_msg .= '<br /><br />';
0909 $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?';
0910 $smtp->close_session($err_msg);
0911 return false;
0912 }
0913
0914 // Ok now we tell the server we are ready to start sending data
0915 $smtp->server_send('DATA');
0916
0917 // This is the last response code we look for until the end of the message.
0918 if ($err_msg = $smtp->server_parse('354', __LINE__))
0919 {
0920 $smtp->close_session($err_msg);
0921 return false;
0922 }
0923
0924 // Send the Subject Line...
0925 $smtp->server_send("Subject: $subject");
0926
0927 // Now the To Header.
0928 $to_header = ($to_header == '') ? 'undisclosed-recipients:;' : $to_header;
0929 $smtp->server_send("To: $to_header");
0930
0931 // Now the CC Header.
0932 if ($cc_header != '')
0933 {
0934 $smtp->server_send("CC: $cc_header");
0935 }
0936
0937 // Now any custom headers....
0938 $smtp->server_send("$headers\r\n");
0939
0940 // Ok now we are ready for the message...
0941 $smtp->server_send($message);
0942
0943 // Ok the all the ingredients are mixed in let's cook this puppy...
0944 $smtp->server_send('.');
0945 if ($err_msg = $smtp->server_parse('250', __LINE__))
0946 {
0947 $smtp->close_session($err_msg);
0948 return false;
0949 }
0950
0951 // Now tell the server we are done and close the socket...
0952 $smtp->server_send('QUIT');
0953 $smtp->close_session($err_msg);
0954
0955 return true;
0956 }
0957
0958 /**
0959 * SMTP Class
0960 * Auth Mechanisms originally taken from the AUTH Modules found within the PHP Extension and Application Repository (PEAR)
0961 * See docs/AUTHORS for more details
0962 * @package phpBB3
0963 */
0964 class smtp_class
0965 {
0966 var $server_response = '';
0967 var $socket = 0;
0968 var $responses = array();
0969 var $commands = array();
0970 var $numeric_response_code = 0;
0971
0972 var $backtrace = false;
0973 var $backtrace_log = array();
0974
0975 function smtp_class()
0976 {
0977 // Always create a backtrace for admins to identify SMTP problems
0978 $this->backtrace = true;
0979 $this->backtrace_log = array();
0980 }
0981
0982 /**
0983 * Add backtrace message for debugging
0984 */
0985 function add_backtrace($message)
0986 {
0987 if ($this->backtrace)
0988 {
0989 $this->backtrace_log[] = utf8_htmlspecialchars($message);
0990 }
0991 }
0992
0993 /**
0994 * Send command to smtp server
0995 */
0996 function server_send($command, $private_info = false)
0997 {
0998 fputs($this->socket, $command . "\r\n");
0999
1000 (!$private_info) ? $this->add_backtrace("# $command") : $this->add_backtrace('# Omitting sensitive information');
1001
1002 // We could put additional code here
1003 }
1004
1005 /**
1006 * We use the line to give the support people an indication at which command the error occurred
1007 */
1008 function server_parse($response, $line)
1009 {
1010 global $user;
1011
1012 $this->server_response = '';
1013 $this->responses = array();
1014 $this->numeric_response_code = 0;
1015
1016 while (substr($this->server_response, 3, 1) != ' ')
1017 {
1018 if (!($this->server_response = fgets($this->socket, 256)))
1019 {
1020 return (isset($user->lang['NO_EMAIL_RESPONSE_CODE'])) ? $user->lang['NO_EMAIL_RESPONSE_CODE'] : 'Could not get mail server response codes';
1021 }
1022 $this->responses[] = substr(rtrim($this->server_response), 4);
1023 $this->numeric_response_code = (int) substr($this->server_response, 0, 3);
1024
1025 $this->add_backtrace("LINE: $line <- {$this->server_response}");
1026 }
1027
1028 if (!(substr($this->server_response, 0, 3) == $response))
1029 {
1030 $this->numeric_response_code = (int) substr($this->server_response, 0, 3);
1031 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";
1032 }
1033
1034 return 0;
1035 }
1036
1037 /**
1038 * Close session
1039 */
1040 function close_session(&$err_msg)
1041 {
1042 fclose($this->socket);
1043
1044 if ($this->backtrace)
1045 {
1046 $message = '<h1>Backtrace</h1><p>' . implode('<br />', $this->backtrace_log) . '</p>';
1047 $err_msg .= $message;
1048 }
1049 }
1050
1051 /**
1052 * Log into server and get possible auth codes if neccessary
1053 */
1054 function log_into_server($hostname, $username, $password, $default_auth_method)
1055 {
1056 global $user;
1057
1058 $err_msg = '';
1059 $local_host = php_uname('n');
1060 $local_host = (empty($local_host)) ? 'localhost' : $local_host;
1061
1062 // If we are authenticating through pop-before-smtp, we
1063 // have to login ones before we get authenticated
1064 // NOTE: on some configurations the time between an update of the auth database takes so
1065 // long that the first email send does not work. This is not a biggie on a live board (only
1066 // the install mail will most likely fail) - but on a dynamic ip connection this might produce
1067 // severe problems and is not fixable!
1068 if ($default_auth_method == 'POP-BEFORE-SMTP' && $username && $password)
1069 {
1070 global $config;
1071
1072 $errno = 0;
1073 $errstr = '';
1074
1075 $this->server_send("QUIT");
1076 fclose($this->socket);
1077
1078 $result = $this->pop_before_smtp($hostname, $username, $password);
1079 $username = $password = $default_auth_method = '';
1080
1081 // We need to close the previous session, else the server is not
1082 // able to get our ip for matching...
1083 if (!$this->socket = @fsockopen($config['smtp_host'], $config['smtp_port'], $errno, $errstr, 10))
1084 {
1085 if ($errstr)
1086 {
1087 $errstr = utf8_convert_message($errstr);
1088 }
1089
1090 $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";
1091 return $err_msg;
1092 }
1093
1094 // Wait for reply
1095 if ($err_msg = $this->server_parse('220', __LINE__))
1096 {
1097 $this->close_session($err_msg);
1098 return $err_msg;
1099 }
1100 }
1101
1102 // Try EHLO first
1103 $this->server_send("EHLO {$local_host}");
1104 if ($err_msg = $this->server_parse('250', __LINE__))
1105 {
1106 // a 503 response code means that we're already authenticated
1107 if ($this->numeric_response_code == 503)
1108 {
1109 return false;
1110 }
1111
1112 // If EHLO fails, we try HELO
1113 $this->server_send("HELO {$local_host}");
1114 if ($err_msg = $this->server_parse('250', __LINE__))
1115 {
1116 return ($this->numeric_response_code == 503) ? false : $err_msg;
1117 }
1118 }
1119
1120 foreach ($this->responses as $response)
1121 {
1122 $response = explode(' ', $response);
1123 $response_code = $response[0];
1124 unset($response[0]);
1125 $this->commands[$response_code] = implode(' ', $response);
1126 }
1127
1128 // If we are not authenticated yet, something might be wrong if no username and passwd passed
1129 if (!$username || !$password)
1130 {
1131 return false;
1132 }
1133
1134 if (!isset($this->commands['AUTH']))
1135 {
1136 return (isset($user->lang['SMTP_NO_AUTH_SUPPORT'])) ? $user->lang['SMTP_NO_AUTH_SUPPORT'] : 'SMTP server does not support authentication';
1137 }
1138
1139 // Get best authentication method
1140 $available_methods = explode(' ', $this->commands['AUTH']);
1141
1142 // Define the auth ordering if the default auth method was not found
1143 $auth_methods = array('PLAIN', 'LOGIN', 'CRAM-MD5', 'DIGEST-MD5');
1144 $method = '';
1145
1146 if (in_array($default_auth_method, $available_methods))
1147 {
1148 $method = $default_auth_method;
1149 }
1150 else
1151 {
1152 foreach ($auth_methods as $_method)
1153 {
1154 if (in_array($_method, $available_methods))
1155 {
1156 $method = $_method;
1157 break;
1158 }
1159 }
1160 }
1161
1162 if (!$method)
1163 {
1164 return (isset($user->lang['NO_SUPPORTED_AUTH_METHODS'])) ? $user->lang['NO_SUPPORTED_AUTH_METHODS'] : 'No supported authentication methods';
1165 }
1166
1167 $method = strtolower(str_replace('-', '_', $method));
1168 return $this->$method($username, $password);
1169 }
1170
1171 /**
1172 * Pop before smtp authentication
1173 */
1174 function pop_before_smtp($hostname, $username, $password)
1175 {
1176 global $user;
1177
1178 if (!$this->socket = @fsockopen($hostname, 110, $errno, $errstr, 10))
1179 {
1180 if ($errstr)
1181 {
1182 $errstr = utf8_convert_message($errstr);
1183 }
1184
1185 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";
1186 }
1187
1188 $this->server_send("USER $username", true);
1189 if ($err_msg = $this->server_parse('+OK', __LINE__))
1190 {
1191 return $err_msg;
1192 }
1193
1194 $this->server_send("PASS $password", true);
1195 if ($err_msg = $this->server_parse('+OK', __LINE__))
1196 {
1197 return $err_msg;
1198 }
1199
1200 $this->server_send('QUIT');
1201 fclose($this->socket);
1202
1203 return false;
1204 }
1205
1206 /**
1207 * Plain authentication method
1208 */
1209 function plain($username, $password)
1210 {
1211 $this->server_send('AUTH PLAIN');
1212 if ($err_msg = $this->server_parse('334', __LINE__))
1213 {
1214 return ($this->numeric_response_code == 503) ? false : $err_msg;
1215 }
1216
1217 $base64_method_plain = base64_encode("\0" . $username . "\0" . $password);
1218 $this->server_send($base64_method_plain, true);
1219 if ($err_msg = $this->server_parse('235', __LINE__))
1220 {
1221 return $err_msg;
1222 }
1223
1224 return false;
1225 }
1226
1227 /**
1228 * Login authentication method
1229 */
1230 function login($username, $password)
1231 {
1232 $this->server_send('AUTH LOGIN');
1233 if ($err_msg = $this->server_parse('334', __LINE__))
1234 {
1235 return ($this->numeric_response_code == 503) ? false : $err_msg;
1236 }
1237
1238 $this->server_send(base64_encode($username), true);
1239 if ($err_msg = $this->server_parse('334', __LINE__))
1240 {
1241 return $err_msg;
1242 }
1243
1244 $this->server_send(base64_encode($password), true);
1245 if ($err_msg = $this->server_parse('235', __LINE__))
1246 {
1247 return $err_msg;
1248 }
1249
1250 return false;
1251 }
1252
1253 /**
1254 * cram_md5 authentication method
1255 */
1256 function cram_md5($username, $password)
1257 {
1258 $this->server_send('AUTH CRAM-MD5');
1259 if ($err_msg = $this->server_parse('334', __LINE__))
1260 {
1261 return ($this->numeric_response_code == 503) ? false : $err_msg;
1262 }
1263
1264 $md5_challenge = base64_decode($this->responses[0]);
1265 $password = (strlen($password) > 64) ? pack('H32', md5($password)) : ((strlen($password) < 64) ? str_pad($password, 64, chr(0)) : $password);
1266 $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))));
1267
1268 $base64_method_cram_md5 = base64_encode($username . ' ' . $md5_digest);
1269
1270 $this->server_send($base64_method_cram_md5, true);
1271 if ($err_msg = $this->server_parse('235', __LINE__))
1272 {
1273 return $err_msg;
1274 }
1275
1276 return false;
1277 }
1278
1279 /**
1280 * digest_md5 authentication method
1281 * A real pain in the ***
1282 */
1283 function digest_md5($username, $password)
1284 {
1285 global $config, $user;
1286
1287 $this->server_send('AUTH DIGEST-MD5');
1288 if ($err_msg = $this->server_parse('334', __LINE__))
1289 {
1290 return ($this->numeric_response_code == 503) ? false : $err_msg;
1291 }
1292
1293 $md5_challenge = base64_decode($this->responses[0]);
1294
1295 // Parse the md5 challenge - from AUTH_SASL (PEAR)
1296 $tokens = array();
1297 while (preg_match('/^([a-z-]+)=("[^"]+(?<!\\\)"|[^,]+)/i', $md5_challenge, $matches))
1298 {
1299 // Ignore these as per rfc2831
1300 if ($matches[1] == 'opaque' || $matches[1] == 'domain')
1301 {
1302 $md5_challenge = substr($md5_challenge, strlen($matches[0]) + 1);
1303 continue;
1304 }
1305
1306 // Allowed multiple "realm" and "auth-param"
1307 if (!empty($tokens[$matches[1]]) && ($matches[1] == 'realm' || $matches[1] == 'auth-param'))
1308 {
1309 if (is_array($tokens[$matches[1]]))
1310 {
1311 $tokens[$matches[1]][] = preg_replace('/^"(.*)"$/', '\\1', $matches[2]);
1312 }
1313 else
1314 {
1315 $tokens[$matches[1]] = array($tokens[$matches[1]], preg_replace('/^"(.*)"$/', '\\1', $matches[2]));
1316 }
1317 }
1318 else if (!empty($tokens[$matches[1]])) // Any other multiple instance = failure
1319 {
1320 $tokens = array();
1321 break;
1322 }
1323 else
1324 {
1325 $tokens[$matches[1]] = preg_replace('/^"(.*)"$/', '\\1', $matches[2]);
1326 }
1327
1328 // Remove the just parsed directive from the challenge
1329 $md5_challenge = substr($md5_challenge, strlen($matches[0]) + 1);
1330 }
1331
1332 // Realm
1333 if (empty($tokens['realm']))
1334 {
1335 $tokens['realm'] = php_uname('n');
1336 }
1337
1338 // Maxbuf
1339 if (empty($tokens['maxbuf']))
1340 {
1341 $tokens['maxbuf'] = 65536;
1342 }
1343
1344 // Required: nonce, algorithm
1345 if (empty($tokens['nonce']) || empty($tokens['algorithm']))
1346 {
1347 $tokens = array();
1348 }
1349 $md5_challenge = $tokens;
1350
1351 if (!empty($md5_challenge))
1352 {
1353 $str = '';
1354 for ($i = 0; $i < 32; $i++)
1355 {
1356 $str .= chr(mt_rand(0, 255));
1357 }
1358 $cnonce = base64_encode($str);
1359
1360 $digest_uri = 'smtp/' . $config['smtp_host'];
1361
1362 $auth_1 = sprintf('%s:%s:%s', pack('H32', md5(sprintf('%s:%s:%s', $username, $md5_challenge['realm'], $password))), $md5_challenge['nonce'], $cnonce);
1363 $auth_2 = 'AUTHENTICATE:' . $digest_uri;
1364 $response_value = md5(sprintf('%s:%s:00000001:%s:auth:%s', md5($auth_1), $md5_challenge['nonce'], $cnonce, md5($auth_2)));
1365
1366 $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']);
1367 }
1368 else
1369 {
1370 return (isset($user->lang['INVALID_DIGEST_CHALLENGE'])) ? $user->lang['INVALID_DIGEST_CHALLENGE'] : 'Invalid digest challenge';
1371 }
1372
1373 $base64_method_digest_md5 = base64_encode($input_string);
1374 $this->server_send($base64_method_digest_md5, true);
1375 if ($err_msg = $this->server_parse('334', __LINE__))
1376 {
1377 return $err_msg;
1378 }
1379
1380 $this->server_send(' ');
1381 if ($err_msg = $this->server_parse('235', __LINE__))
1382 {
1383 return $err_msg;
1384 }
1385
1386 return false;
1387 }
1388 }
1389
1390 /**
1391 * Encodes the given string for proper display in UTF-8.
1392 *
1393 * This version is using base64 encoded data. The downside of this
1394 * is if the mail client does not understand this encoding the user
1395 * is basically doomed with an unreadable subject.
1396 *
1397 * Please note that this version fully supports RFC 2045 section 6.8.
1398 */
1399 function mail_encode($str)
1400 {
1401 // define start delimimter, end delimiter and spacer
1402 $start = "=?UTF-8?B?";
1403 $end = "?=";
1404 $spacer = $end . ' ' . $start;
1405 $split_length = 64;
1406
1407 $encoded_str = base64_encode($str);
1408
1409 // If encoded string meets the limits, we just return with the correct data.
1410 if (strlen($encoded_str) <= $split_length)
1411 {
1412 return $start . $encoded_str . $end;
1413 }
1414
1415 // If there is only ASCII data, we just return what we want, correctly splitting the lines.
1416 if (strlen($str) === utf8_strlen($str))
1417 {
1418 return $start . implode($spacer, str_split($encoded_str, $split_length)) . $end;
1419 }
1420
1421 // UTF-8 data, compose encoded lines
1422 $array = utf8_str_split($str);
1423 $str = '';
1424
1425 while (sizeof($array))
1426 {
1427 $text = '';
1428
1429 while (sizeof($array) && intval((strlen($text . $array[0]) + 2) / 3) << 2 <= $split_length)
1430 {
1431 $text .= array_shift($array);
1432 }
1433
1434 $str .= $start . base64_encode($text) . $end . ' ';
1435 }
1436
1437 return substr($str, 0, -1);
1438 }
1439
1440 ?>