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.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

      (Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

functions_messenger.php

Zuletzt modifiziert: 09.10.2024, 12:50 - Dateigröße: 35.57 KiB


 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  ?>