)/me(?: | )(.*?)([\r\n]|
|\z)~i', '$1[me="' . $user_info['name'] . '"]$2[/me]$3', $message); else $message = preg_replace('~(\A|\n|
)/me(?: | )(.*?)([\r\n]|
|\z)~i', '$1[me=' . $user_info['name'] . ']$2[/me]$3', $message); // Remove \r's, replace tabs with spaces, two spaces with hard spaces, and \n's with breaks. (last is optional...) $message = strtr($message, array("\r" => '', ' ' => '  ')); if ($breaks) $message = strtr($message, array("\n" => '
')); // Check if all quotes are closed... $parts = preg_split('~(\[/quote\])~i', $message, -1, PREG_SPLIT_DELIM_CAPTURE); $level = 0; for ($i = 0, $n = count($parts); $i < $n; $i++) { if (preg_match('~\[/quote\]~i',$parts[$i]) != 0) $level--; preg_match_all('~(\[quote=.+?\])|(\[quote author=.+?\])|(\[quote author=(.+?) link=(.+?) date=(.+?)\])|(\[quote\])~i', $parts[$i], $regs); $level += count($regs[0]); // Add on extra [quote]s... if ($level < 0) { $parts[$i] = str_repeat('[quote]', 0 - $level) . $parts[$i]; $level = 0; } } $message = implode('', $parts); // Add additional [/quote]s to the end. if ($level > 0) $message .= str_repeat('[/quote]', $level); // Check if all code tags are closed. $codeopen = preg_match_all('~(?!\[)(\[code\])~i', $message, $dummy); $codeclose = preg_match_all('~(?!\[)(\[/code\])~i', $message, $dummy); // Close/open all code tags... if ($codeopen > $codeclose) $message .= str_repeat('[/code]', $codeopen - $codeclose); elseif ($codeclose > $codeopen) $message = str_repeat('[code]', $codeclose - $codeopen) . $message; // Now that we've fixed all the code tags, let's fix the img and url tags... $parts = preg_split('~\[/?code\]~i', $message); // Only mess with stuff outside [code] tags. for ($i = 0, $n = count($parts); $i < $n; $i++) { // 1 (odd) means a code section, not post text. if ($i % 2 == 1) $parts[$i] = '[code]' . $parts[$i] . '[/code]'; // Mess with the tags outside [code]. else fixTags($parts[$i]); } // Put it back together and remove that first space. $message = implode('', $parts); } // Fix any URLs posted - ie. remove 'javascript:'. function fixTags(&$message) { global $modSettings; $fixArray = array ( // [img]http://...[/img] or [img width=1]http://...[/img] array('tag' => 'img', 'protocol' => 'http', 'embeddedUrl' => false, 'hasEqualSign' => false, 'hasExtra' => true), // [url]http://...[/url] array('tag' => 'url', 'protocol' => 'http', 'embeddedUrl' => true, 'hasEqualSign' => false), // [url=http://...]name[/url] array('tag' => 'url', 'protocol' => 'http', 'embeddedUrl' => true, 'hasEqualSign' => true), // [iurl]http://...[/iurl] array('tag' => 'iurl', 'protocol' => 'http', 'embeddedUrl' => true, 'hasEqualSign' => false), // [iurl=http://...]name[/iurl] array('tag' => 'iurl', 'protocol' => 'http', 'embeddedUrl' => true, 'hasEqualSign' => true), // [ftp]ftp://...[/ftp] array('tag' => 'ftp', 'protocol' => 'ftp', 'embeddedUrl' => true, 'hasEqualSign' => false), // [ftp=ftp://...]name[/ftp] array('tag' => 'ftp', 'protocol' => 'ftp', 'embeddedUrl' => true, 'hasEqualSign' => true), // [flash]http://...[/flash] array('tag' => 'flash', 'protocol' => 'http', 'embeddedUrl' => false, 'hasEqualSign' => true, 'hasExtra' => true) ); // Fix each type of tag. foreach ($fixArray as $param) fixTag($message, $param['tag'], $param['protocol'], $param['embeddedUrl'], $param['hasEqualSign'], isset($param['hasExtra'])); // Now fix possible security problems with images loading links automatically... $message = preg_replace('~(\[img.*?\])(.+?)\[/img\]~eis', '\'$1\' . preg_replace(\'~action(=|%3d)(?!dlattach)~i\', \'action-\', \'$2\') . \'[/img]\'', $message); // Limit the size of images posted? if (!empty($modSettings['maxwidth']) || !empty($modSettings['maxheight'])) { // Find all the img tags - with or without width and height. preg_match_all('~\[img(\s+width=\d+)?(\s+height=\d+)?(\s+width=\d+)?\](.+?)\[/img\]~is', $message, $matches, PREG_PATTERN_ORDER); $replaces = array(); foreach ($matches[0] as $match => $dummy) { // If the width was after the height, handle it. $matches[1][$match] = !empty($matches[3][$match]) ? $matches[3][$match] : $matches[1][$match]; // Now figure out if they had a desired height or width... $desired_width = !empty($matches[1][$match]) ? (int) substr(trim($matches[1][$match]), 6) : 0; $desired_height = !empty($matches[2][$match]) ? (int) substr(trim($matches[2][$match]), 7) : 0; // One was omitted, or both. We'll have to find its real size... if (empty($desired_width) || empty($desired_height)) { list ($width, $height) = url_image_size($matches[4][$match]); // They don't have any desired width or height! if (empty($desired_width) && empty($desired_height)) { $desired_width = $width; $desired_height = $height; } // Scale it to the width... elseif (empty($desired_width)) $desired_width = (int) (($desired_height * $width) / $height); // Scale if to the height. else $desired_height = (int) (($desired_width * $height) / $width); } // If the width and height are fine, just continue along... if ($desired_width <= $modSettings['maxwidth'] && $desired_height <= $modSettings['maxheight']) continue; // Too bad, it's too wide. Make it as wide as the maximum. if ($desired_width > $modSettings['maxwidth'] && !empty($modSettings['maxwidth'])) { $desired_height = (int) (($modSettings['maxwidth'] * $desired_height) / $desired_width); $desired_width = $modSettings['maxwidth']; } // Now check the height, as well. Might have to scale twice, even... if ($desired_height > $modSettings['maxheight'] && !empty($modSettings['maxheight'])) { $desired_width = (int) (($modSettings['maxheight'] * $desired_width) / $desired_height); $desired_height = $modSettings['maxheight']; } $replaces[$matches[0][$match]] = '[img width=' . $desired_width . ' height=' . $desired_height . ']' . $matches[4][$match] . '[/img]'; } // If any img tags were actually changed... if (!empty($replaces)) $message = strtr($message, $replaces); } } // Fix a specific class of tag - ie. url with =. function fixTag(&$message, $myTag, $protocol, $embeddedUrl = false, $hasEqualSign = false, $hasExtra = false) { while (preg_match('/\[(' . $myTag . ($hasExtra ? '(?:[^\]]*?)' : '') . ')' . ($hasEqualSign ? '(=([^\]]*?))' : '(())') . '\](.+?)\[\/(' . $myTag . ')\]/is', $message, $matches)) { // All the different information from the match. $leftTag = $matches[1]; $equalTo = $matches[3]; $searchfor = $matches[4]; $rightTag = $matches[5]; $replace = $hasEqualSign && $embeddedUrl ? $equalTo : $searchfor; // Remove all leading and trailing whitespace. $replace = trim($replace); if (!stristr($replace, $protocol . '://')) { if ($protocol != 'http' || !stristr($replace, 'https://')) $replace = $protocol . '://' . $replace; else $replace = stristr($replace, 'https://'); } else $replace = stristr($replace, $protocol . '://'); // Put the tag back together. if ($hasEqualSign && $embeddedUrl) $message = str_replace( '[' . $leftTag . '=' . $equalTo . ']' . $searchfor . '[/' . $rightTag . ']', '<' . $myTag . '=' . $replace . ']' . $searchfor . '', $message); elseif ($hasEqualSign && !$embeddedUrl) $message = str_replace( '[' . $leftTag . '=' . $equalTo . ']' . $searchfor . '[/' . $rightTag . ']', '<' . $myTag . '=' . $equalTo . ']' . $replace . '', $message); elseif ($embeddedUrl && $replace != $searchfor) $message = str_replace( '[' . $leftTag . ']' . $searchfor . '[/' . $rightTag . ']', '<' . $myTag . '=' . $replace . ']' . $searchfor . '', $message); else $message = str_replace( '[' . $leftTag . ']' . $searchfor . '[/' . $rightTag . ']', '<' . preg_replace('~' . preg_quote($myTag) . '~i', $myTag, $leftTag) . '>' . $replace . '', $message); } // Replace the braces with brackets. $message = str_replace( array('<' . $myTag . '>', '<' . $myTag . '=', ''), array('[' . $myTag . ']', '[' . $myTag . '=', '[/' . $myTag . ']'), $message); // If there is extra stuff we also need to do this. (flash, img.) if ($hasExtra) $message = preg_replace('~<(' . $myTag . '.+?)>~i', '[$1]', $message); } // Send off an email. function sendmail($to, $subject, $message, $from = null, $send_html = false) { global $webmaster_email, $context, $modSettings, $txt, $scripturl; $reply_to = $from !== null ? $from : null; $from = array( $webmaster_email => $from !== null ? $from : $context['forum_name'] ); require_once '/var/www/lib/swiftmailer/lib/swift_required.php'; $transport = Swift_MailTransport::newInstance(); $mailer = Swift_Mailer::newInstance($transport); $email = Swift_Message::newInstance($subject) ->setFrom($from) ->setTo($to) ->setReturnPath($webmaster_email) ->setBody($message); if ($reply_to !== null) $email->setReplyTo($reply_to); return $mailer->send($email); } // Send off a personal message. function sendpm($recipients, $subject, $message, $store_outbox, $from = null) { global $db_prefix, $ID_MEMBER, $scripturl, $txt, $user_info, $language; // Initialize log array. $log = array( 'failed' => array(), 'sent' => array() ); if ($from === null) $from = array( 'id' => $ID_MEMBER, 'name' => $user_info['name'], 'username' => $user_info['username'] ); // Probably not needed. /me something should be of the typer. else $user_info['name'] = $from['name']; // This is the one that will go in their inbox. $htmlmessage = htmlspecialchars($message, ENT_QUOTES); $htmlsubject = htmlspecialchars($subject); preparsecode($htmlmessage); // Get a list of usernames and convert them to IDs. $usernames = array(); foreach ($recipients as $rec_type => $rec) { foreach ($rec as $id => $member) { if (!is_numeric($recipients[$rec_type][$id])) { $recipients[$rec_type][$id] = strtolower(trim(preg_replace('/[<>&"\'=\\\]/', '', $recipients[$rec_type][$id]))); $usernames[$recipients[$rec_type][$id]] = 0; } } } if (!empty($usernames)) { $request = db_query(" SELECT ID_MEMBER, memberName FROM {$db_prefix}members WHERE memberName IN ('" . explode("', '", array_keys($usernames)) . "')", __FILE__, __LINE__); while ($row = mysql_fetch_assoc($request)) if (isset($usernames[strtolower($row['memberName'])])) $usernames[strtolower($row['memberName'])] = $row['ID_MEMBER']; // Replace the usernames with IDs. Drop usernames that couldn't be found. foreach ($recipients as $rec_type => $rec) foreach ($rec as $id => $member) { if (is_numeric($recipients[$rec_type][$id])) continue; if (!empty($usernames[$member])) $recipients[$rec_type][$id] = $usernames[$member]; else { $log['failed'][] = sprintf($txt['pm_error_user_not_found'], $recipients[$rec_type][$id]); unset($recipients[$rec_type][$id]); } } } // Make sure there are no duplicate 'to' members. $recipients['to'] = array_unique($recipients['to']); // Only 'bcc' members that aren't already in 'to'. $recipients['bcc'] = array_diff(array_unique($recipients['bcc']), $recipients['to']); // Combine 'to' and 'bcc' recipients. $all_to = array_merge($recipients['to'], $recipients['bcc']); $request = db_query(" SELECT mem.memberName, mem.realName, mem.ID_MEMBER, mem.emailAddress, mem.lngfile, mg.maxMessages, mem.im_email_notify, mem.instantMessages," . (allowedTo('moderate_forum') ? ' 0' : " (mem.im_ignore_list = '*' OR FIND_IN_SET($from[id], mem.im_ignore_list))") . " AS ignored FROM {$db_prefix}members AS mem LEFT JOIN {$db_prefix}membergroups AS mg ON (mg.ID_GROUP = IF(mem.ID_GROUP = 0, mem.ID_POST_GROUP, mem.ID_GROUP)) WHERE mem.ID_MEMBER IN (" . implode(", ", $all_to) . ") ORDER BY mem.lngfile LIMIT " . count($all_to), __FILE__, __LINE__); $notifications = array(); while ($row = mysql_fetch_assoc($request)) { if (!empty($row['maxMessages']) && $row['maxMessages'] <= $row['instantMessages'] && !allowedTo('moderate_forum')) { $log['failed'][] = sprintf($txt['pm_error_data_limit_reached'], $row['realName']); unset($all_to[array_search($row['ID_MEMBER'], $all_to)]); continue; } if (!empty($row['ignored'])) { $log['failed'][] = sprintf($txt['pm_error_ignored_by_user'], $row['realName']); unset($all_to[array_search($row['ID_MEMBER'], $all_to)]); continue; } // Send a notification, if enabled. if (!empty($row['im_email_notify']) && !empty($row['emailAddress'])) $notifications[empty($row['lngfile']) || empty($modSettings['userLanguage']) ? $language : $row['lngfile']][] = $row['emailAddress']; $log['sent'][] = sprintf($txt['pm_successfully_sent'], $row['realName']); } mysql_free_result($request); // Only 'send' the message if there are any recipients left. if (empty($all_to)) return $log; // Insert the message itself and then grab the last insert id. db_query(" INSERT INTO {$db_prefix}instant_messages (ID_MEMBER_FROM, deletedBySender, fromName, msgtime, subject, body) VALUES ($from[id], " . ($store_outbox ? '0' : '1') . ", '$from[username]', " . time() . ", '$htmlsubject', '$htmlmessage')", __FILE__, __LINE__); $ID_PM = db_insert_id(); // Some people think manually deleting instant_messages is fun... it's not. We protect against it though :) db_query(" DELETE FROM {$db_prefix}im_recipients WHERE ID_PM = $ID_PM", __FILE__, __LINE__); // Add the recipients. if (!empty($ID_PM)) { $insertRows = array(); foreach ($all_to as $to) $insertRows[] = "($ID_PM, $to, " . (in_array($to, $recipients['bcc']) ? '1' : '0') . ')'; db_query(" INSERT INTO {$db_prefix}im_recipients (ID_PM, ID_MEMBER, bcc) VALUES " . implode(', ', $insertRows), __FILE__, __LINE__); } foreach ($notifications as $lang => $notification_list) { // Make sure to use the right language. loadLanguage('InstantMessage', $lang, false); // Replace the right things in the message strings. $mailsubject = str_replace(array('SUBJECT', 'SENDER'), array($subject, $from['name']), $txt[561]); $mailmessage = str_replace(array('SUBJECT', 'MESSAGE', 'SENDER'), array($subject, $message, $from['name']), $txt[562]); $mailmessage .= "\n\n" . $txt['instant_reply'] . ' ' . $scripturl . '?action=pm;sa=send;f=inbox;pmsg=' . $ID_PM . ';quote;u=' . $from['id']; // Off the notification email goes! sendmail($notification_list, $mailsubject, $mailmessage); } // Add one to their unread and read message counts. updateMemberData($all_to, array('instantMessages' => '+', 'unreadMessages' => '+')); return $log; } // Send an email via SMTP. function smtp_mail($mail_to_array, $subject, $message, $headers) { global $modSettings, $webmaster_email, $txt; // Try to connect to the SMTP server... if it doesn't exist, only wait five seconds. if (!$socket = fsockopen($modSettings['smtp_host'], empty($modSettings['smtp_port']) ? 25 : $modSettings['smtp_port'], $errno, $errstr, 5)) { // Unable to connect! Don't show any error message, but just log one and try to continue anyway. log_error($txt['smtp_no_connect'] . ' : ' . $errno . ' : ' . $errstr); return false; } // Wait for a response of 220, without "-" continuer. if (!server_parse(null, $socket, '220')) return false; if ($modSettings['smtp_username'] != '' && $modSettings['smtp_password'] != '') { // EHLO could be understood to mean encrypted hello... if (!server_parse('EHLO ' . $modSettings['smtp_host'], $socket, '250')) return false; if (!server_parse('AUTH LOGIN', $socket, '334')) return false; // Send the username ans password, encoded. if (!server_parse(base64_encode($modSettings['smtp_username']), $socket, '334')) return false; if (!server_parse(base64_encode($modSettings['smtp_password']), $socket, '235')) return false; } else { // Just say "helo". if (!server_parse('HELO ' . $modSettings['smtp_host'], $socket, '250')) return false; } foreach ($mail_to_array as $mail_to) { // From, to, and then start the data... if (!server_parse('MAIL FROM: <' . $webmaster_email . '>', $socket, '250')) return false; if (!server_parse('RCPT TO: <' . $mail_to . '>', $socket, '250')) return false; if (!server_parse('DATA', $socket, '354')) return false; fputs($socket, 'Subject: ' . $subject . "\r\n"); if (strlen($mail_to) > 0) fputs($socket, 'To: <' . $mail_to . ">\r\n"); fputs($socket, $headers . "\r\n\r\n"); fputs($socket, $message . "\r\n"); // Send a ., or in other words "end of data". if (!server_parse('.', $socket, '250')) return false; // Reset the connection to send another email. if (!server_parse('RSET', $socket, '250')) return false; } fputs($socket, "QUIT\r\n"); fclose($socket); return true; } // Parse a message to the SMTP server. function server_parse($message, $socket, $response) { global $txt; if ($message !== null) fputs($socket, $message . "\r\n"); // No response yet. $server_response = ''; while (substr($server_response, 3, 1) != ' ') if (!($server_response = fgets($socket, 256))) { log_error($txt['smtp_bad_response']); return false; } if (substr($server_response, 0, 3) != $response) { log_error($txt['smtp_error'] . $server_response); return false; } return true; } // Makes sure the calendar post is valid. function calendarValidatePost() { global $modSettings, $txt, $sourcedir; if (!isset($_POST['deleteevent'])) { // No month? No year? if (!isset($_POST['month'])) fatal_lang_error('calendar7', false); if (!isset($_POST['year'])) fatal_lang_error('calendar8', false); // Check the month and year... if ($_POST['month'] < 1 || $_POST['month'] > 12) fatal_lang_error('calendar1', false); if ($_POST['year'] < $modSettings['cal_minyear'] || $_POST['year'] > $modSettings['cal_maxyear']) fatal_lang_error('calendar2', false); } // Make sure they're allowed to post... isAllowedTo('calendar_post'); if (isset($_POST['span'])) { // Make sure it's turned on and not some fool trying to trick it. if ($modSettings['cal_allowspan'] != 1) fatal_lang_error('calendar55', false); if ($_POST['span'] < 1 || $_POST['span'] > $modSettings['cal_maxspan']) fatal_lang_error('calendar56', false); } // There is no need to validate the following values if we are just deleting the event. if (!isset($_POST['deleteevent'])) { // No day? if (!isset($_POST['day'])) fatal_lang_error('calendar14', false); if (!isset($_POST['evtitle']) && !isset($_POST['subject'])) fatal_lang_error('calendar15', false); elseif (!isset($_POST['evtitle'])) $_POST['evtitle'] = $_POST['subject']; // Bad day? if (!checkdate($_POST['month'], $_POST['day'], $_POST['year'])) fatal_lang_error('calendar16', false); // No title? if (trim($_POST['evtitle']) == '') fatal_lang_error('calendar17', false); if (strlen($_POST['evtitle']) > 30) $_POST['evtitle'] = substr($_POST['evtitle'], 0, 30); $_POST['evtitle'] = str_replace(';', '', $_POST['evtitle']); } } // Prints a post box. Used everywhere you post or send. function theme_postbox($msg) { global $txt, $modSettings, $db_prefix; global $context, $settings, $user_info; // Switch between default images and back... mostly in case you don't have an InstantMessage template, but do ahve a Post template. if (isset($settings['use_default_images']) && $settings['use_default_images'] == 'defaults' && isset($settings['default_template'])) { $temp1 = $settings['theme_url']; $settings['theme_url'] = $settings['default_theme_url']; $temp2 = $settings['images_url']; $settings['images_url'] = $settings['default_images_url']; $temp3 = $settings['theme_dir']; $settings['theme_dir'] = $settings['default_theme_dir']; } // Load the Post template and language file. loadTemplate('Post'); loadLanguage('Post'); // Initialize smiley array... $context['smileys'] = array( 'postform' => array(), 'popup' => array(), ); // Load smileys - don't bother to run a query if we're not using the database's ones anyhow. if (empty($modSettings['smiley_enable']) && $user_info['smiley_set'] != 'none') $context['smileys']['postform'][] = array( 'smileys' => array( array('code' => ':)', 'filename' => 'smiley.gif', 'description' => $txt[287]), array('code' => ';)', 'filename' => 'wink.gif', 'description' => $txt[292]), array('code' => ':D', 'filename' => 'cheesy.gif', 'description' => $txt[289]), array('code' => ';D', 'filename' => 'grin.gif', 'description' => $txt[293]), array('code' => '>:(', 'filename' => 'angry.gif', 'description' => $txt[288]), array('code' => ':(', 'filename' => 'sad.gif', 'description' => $txt[291]), array('code' => ':o', 'filename' => 'shocked.gif', 'description' => $txt[294]), array('code' => '8)', 'filename' => 'cool.gif', 'description' => $txt[295]), array('code' => '???', 'filename' => 'huh.gif', 'description' => $txt[296]), array('code' => '::)', 'filename' => 'rolleyes.gif', 'description' => $txt[450]), array('code' => ':P', 'filename' => 'tongue.gif', 'description' => $txt[451]), array('code' => ':-[', 'filename' => 'embarassed.gif', 'description' => $txt[526]), array('code' => ':-X', 'filename' => 'lipsrsealed.gif', 'description' => $txt[527]), array('code' => ':-\\', 'filename' => 'undecided.gif', 'description' => $txt[528]), array('code' => ':-*', 'filename' => 'kiss.gif', 'description' => $txt[529]), array('code' => ':\'(', 'filename' => 'cry.gif', 'description' => $txt[530]) ), 'last' => true, ); elseif ($user_info['smiley_set'] != 'none') { $request = db_query(" SELECT code, filename, description, smileyRow, hidden FROM {$db_prefix}smileys WHERE hidden IN (0, 2) ORDER BY smileyRow, smileyOrder", __FILE__, __LINE__); while ($row = mysql_fetch_assoc($request)) $context['smileys'][empty($row['hidden']) ? 'postform' : 'popup'][$row['smileyRow']]['smileys'][] = $row; mysql_free_result($request); } // Clean house... add slashes to the code for javascript. foreach (array_keys($context['smileys']) as $location) { foreach ($context['smileys'][$location] as $j => $row) { $n = count($context['smileys'][$location][$j]['smileys']); for ($i = 0; $i < $n; $i++) { $context['smileys'][$location][$j]['smileys'][$i]['code'] = addslashes($context['smileys'][$location][$j]['smileys'][$i]['code']); $context['smileys'][$location][$j]['smileys'][$i]['js_description'] = addslashes($context['smileys'][$location][$j]['smileys'][$i]['description']); } $context['smileys'][$location][$j]['smileys'][$n - 1]['last'] = true; } if (!empty($context['smileys'][$location])) $context['smileys'][$location][count($context['smileys'][$location]) - 1]['last'] = true; } $settings['smileys_url'] = $modSettings['smileys_url'] . '/' . $user_info['smiley_set']; // Allow for things to be overridden. if (!isset($context['post_box_columns'])) $context['post_box_columns'] = 60; if (!isset($context['post_box_rows'])) $context['post_box_rows'] = 12; if (!isset($context['post_box_name'])) $context['post_box_name'] = 'message'; if (!isset($context['post_form'])) $context['post_form'] = 'postmodify'; // Set a flag so the sub template knows what to do... $context['show_bbc'] = !empty($modSettings['enableBBC']) && !empty($settings['show_bbc']); // Generate a list of buttons that shouldn't be shown - this should be the fastest way to do this. if (!empty($modSettings['disabledBBC'])) { $disabled_tags = explode(',', $modSettings['disabledBBC']); foreach ($disabled_tags as $tag) $context['disabled_tags'][trim($tag)] = true; } // Go! Supa-sub-template-smash! template_postbox($msg); // Switch the URLs back... now we're back to whatever the main sub template is. (like folder in InstantMessage.) if (isset($settings['use_default_images']) && $settings['use_default_images'] == 'defaults' && isset($settings['default_template'])) { $settings['theme_url'] = $temp1; $settings['images_url'] = $temp2; $settings['theme_dir'] = $temp3; } } function SpellCheck() { global $txt, $context; // A list of "words" we know about but pspell doesn't. $known_words = array('smf', 'php', 'mysql', 'www', 'http', 'smfisawesome', 'grandia', 'terranigma'); loadTemplate('Post'); loadLanguage('Post'); // Okay, this looks funny, but it actually fixes a weird bug. ob_start(); $old = error_reporting(0); // See, first, some windows machines don't load pspell properly on the first try. Dumb, but this is a workaround. pspell_new('en'); // Next, the dictionary in question may not exist. So, we try it... but... $pspell_link = pspell_new($txt['lang_dictionary'], $txt['lang_spelling'], '', strtr($txt['lang_character_set'], array('iso-' => 'iso', 'ISO-' => 'iso')), PSPELL_FAST | PSPELL_RUN_TOGETHER); error_reporting($old); ob_end_clean(); // Most people don't have anything but english installed... so we use english as a last resort. if (!$pspell_link) $pspell_link = pspell_new('en', '', '', '', PSPELL_FAST | PSPELL_RUN_TOGETHER); if (!isset($_POST['spellstring']) || !isset($_POST['spell_formname']) || !isset($_POST['spell_fieldname']) || !$pspell_link) die; // Can't have any \n's or \r's in javascript strings. $mystr = trim(str_replace(array("\r", "\n"), array('', '_|_'), stripslashes($_POST['spellstring']))); preg_match_all('/(?:<[^>]+>)|(?:\[[^ ][^\]]*\])|(?:&[^;\ ]+;)|(?<=^|[^[:alpha:]\'])([[:alpha:]\']+)/is', $mystr, $alphas, PREG_PATTERN_ORDER); // Do this after because the js doesn't count '\"' as two, but PHP does. $context['spell_js'] = ' var txt = {"done": "' . $txt['spellcheck_done'] . '"}; var mispstr = "' . str_replace(array('\\', '"', ''), array('\\\\', '\\"', '<" + "/script>'), $mystr) . '"; var misps = Array('; // This is some sanity checking: they should be chronological. $last_occurance = 0; $found_words = false; $code_block = false; for ($i = 0, $n = count($alphas[0]); $i < $n; $i++) { // Check if we're inside a code block... if (preg_match('~\[/?code\]~i', $alphas[0][$i])) $code_block = !$code_block; // If the word is an html tag, an entity, a bbc tag, inside [code], a known word, or spelled right... if (empty($alphas[1][$i]) || $code_block || in_array(strtolower($alphas[1][$i]), $known_words) || pspell_check($pspell_link, $alphas[1][$i])) { // Add on this word's length, and continue. $last_occurance += strlen($alphas[0][$i]); continue; } // Find the word, and move up the "last occurance" to here. $last_occurance = strpos($mystr, $alphas[0][$i], $last_occurance + 1); $found_words = true; // Add on the javascript for this misspelling. $context['spell_js'] .= ' new misp("' . $alphas[1][$i] . '", ' . (int) $last_occurance . ', ' . ($last_occurance + strlen($alphas[1][$i]) - 1) . ', ['; // If there are suggestions, add them in... $suggestions = pspell_suggest($pspell_link, $alphas[1][$i]); if (!empty($suggestions)) $context['spell_js'] .= '"' . join('", "', $suggestions) . '"'; $context['spell_js'] .= ']),'; } // If words were found, take off the last comma. if ($found_words) $context['spell_js'] = substr($context['spell_js'], 0, -1); $context['spell_js'] .= ' );'; // And instruct the template system to just show the spellcheck sub template. $context['template_layers'] = array(); $context['sub_template'] = 'spellcheck'; } // Notify members that something has happened to a topic they marked! function sendNotifications($ID_TOPIC, $type) { global $txt, $scripturl, $db_prefix, $language, $user_info; global $ID_MEMBER, $modSettings, $sourcedir; $notification_types = array( 'reply' => array('subject' => 'notification_reply_subject', 'message' => 'notification_reply'), 'sticky' => array('subject' => 'notification_sticky_subject', 'message' => 'notification_sticky'), 'lock' => array('subject' => 'notification_lock_subject', 'message' => 'notification_lock'), 'unlock' => array('subject' => 'notification_unlock_subject', 'message' => 'notification_unlock'), 'remove' => array('subject' => 'notification_remove_subject', 'message' => 'notification_remove'), 'move' => array('subject' => 'notification_move_subject', 'message' => 'notification_move'), 'merge' => array('subject' => 'notification_merge_subject', 'message' => 'notification_merge'), 'split' => array('subject' => 'notification_split_subject', 'message' => 'notification_split'), ); $current_type = $notification_types[$type]; // Can't do it if there's no topic. if (empty($ID_TOPIC)) return; // Get the board and subject... $result = db_query(" SELECT ID_BOARD, subject FROM {$db_prefix}messages WHERE ID_TOPIC = $ID_TOPIC ORDER BY ID_MSG LIMIT 1", __FILE__, __LINE__); list ($ID_BOARD, $subject) = mysql_fetch_row($result); mysql_free_result($result); // Censor... censorText($subject); $subject = un_htmlspecialchars($subject); // Find the members with notification on for this topic. $members = db_query(" SELECT mem.ID_MEMBER, mem.emailAddress, mem.notifyOnce, mem.lngfile, ln.sent, mem.ID_GROUP, mem.additionalGroups, b.memberGroups, mem.ID_POST_GROUP FROM {$db_prefix}log_notify AS ln, {$db_prefix}members AS mem, {$db_prefix}topics AS t, {$db_prefix}boards AS b WHERE ln.ID_TOPIC = $ID_TOPIC AND t.ID_TOPIC = $ID_TOPIC AND b.ID_BOARD = $ID_BOARD AND mem.ID_MEMBER != $ID_MEMBER AND ln.ID_MEMBER = mem.ID_MEMBER GROUP BY mem.ID_MEMBER ORDER BY mem.lngfile", __FILE__, __LINE__); while ($row = mysql_fetch_assoc($members)) { if ($row['ID_GROUP'] != 1) { $allowed = explode(',', $row['memberGroups']); $row['additionalGroups'] = explode(',', $row['additionalGroups']); $row['additionalGroups'][] = $row['ID_GROUP']; $row['additionalGroups'][] = $row['ID_POST_GROUP']; if (count(array_intersect($allowed, $row['additionalGroups'])) == 0) continue; } loadLanguage('Post', empty($row['lngfile']) || empty($modSettings['userLanguage']) ? $language : $row['lngfile'], false); $message = sprintf($txt[$current_type['message']], un_htmlspecialchars($user_info['name'])); if ($type != 'remove') $message .= $scripturl . '?topic=' . $ID_TOPIC . '.new;topicseen#new' . "\n\n" . $txt['notifyUnsubscribe'] . ': ' . $scripturl . '?action=notify;topic=' . $ID_TOPIC . '.0'; if (!empty($row['notifyOnce']) && $type == 'reply') $message .= "\n\n" . $txt['notifyXOnce2']; // Send only if once is off or it's on and it hasn't been sent. if ($type != 'reply' || empty($row['notifyOnce']) || empty($row['sent'])) { sendmail($row['emailAddress'], sprintf($txt[$current_type['subject']], $subject), $message . "\n\n" . $txt[130]); } } mysql_free_result($members); // Sent! if ($type == 'reply') db_query(" UPDATE {$db_prefix}log_notify SET sent = 1 WHERE ID_TOPIC = $ID_TOPIC AND ID_MEMBER != $ID_MEMBER", __FILE__, __LINE__); } ?>