Subs-Editor.php 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003
  1. <?php
  2. /**
  3. * This file contains those functions specific to the editing box and is
  4. * generally used for WYSIWYG type functionality.
  5. *
  6. * Simple Machines Forum (SMF)
  7. *
  8. * @package SMF
  9. * @author Simple Machines http://www.simplemachines.org
  10. * @copyright 2011 Simple Machines
  11. * @license http://www.simplemachines.org/about/smf/license.php BSD
  12. *
  13. * @version 2.1 Alpha 1
  14. */
  15. if (!defined('SMF'))
  16. die('Hacking attempt...');
  17. /**
  18. * Creates the javascript code for localization of the editor (SCEditor)
  19. */
  20. function loadLocale()
  21. {
  22. global $context, $txt, $txteditor, $modSettings;
  23. loadLanguage('Editor');
  24. $context['template_layers'] = array();
  25. // Lets make sure we aren't going to output anything nasty.
  26. @ob_end_clean();
  27. if (!empty($modSettings['enableCompressedOutput']))
  28. @ob_start('ob_gzhandler');
  29. else
  30. @ob_start();
  31. // If we don't have any locale better avoit broken js
  32. if (empty($txt['lang_locale']))
  33. die();
  34. $file_data = '(function ($) {
  35. \'use strict\';
  36. $.sceditor.locale[' . javaScriptEscape($txt['lang_locale']) . '] = {';
  37. foreach ($txteditor as $key => $val)
  38. $file_data .= '
  39. ' . javaScriptEscape($key) . ': ' . javaScriptEscape($val) . ',';
  40. $file_data .= '
  41. dateFormat: "day.month.year"
  42. }
  43. })(jQuery);';
  44. // Make sure they know what type of file we are.
  45. header('Content-Type: text/javascript');
  46. echo $file_data;
  47. obExit(false);
  48. }
  49. /**
  50. * Retrieves a list of message icons.
  51. * - Based on the settings, the array will either contain a list of default
  52. * message icons or a list of custom message icons retrieved from the database.
  53. * - The board_id is needed for the custom message icons (which can be set for
  54. * each board individually).
  55. *
  56. * @param int $board_id
  57. * @return array
  58. */
  59. function getMessageIcons($board_id)
  60. {
  61. global $modSettings, $context, $txt, $settings, $smcFunc;
  62. if (empty($modSettings['messageIcons_enable']))
  63. {
  64. loadLanguage('Post');
  65. $icons = array(
  66. array('value' => 'xx', 'name' => $txt['standard']),
  67. array('value' => 'thumbup', 'name' => $txt['thumbs_up']),
  68. array('value' => 'thumbdown', 'name' => $txt['thumbs_down']),
  69. array('value' => 'exclamation', 'name' => $txt['excamation_point']),
  70. array('value' => 'question', 'name' => $txt['question_mark']),
  71. array('value' => 'lamp', 'name' => $txt['lamp']),
  72. array('value' => 'smiley', 'name' => $txt['icon_smiley']),
  73. array('value' => 'angry', 'name' => $txt['icon_angry']),
  74. array('value' => 'cheesy', 'name' => $txt['icon_cheesy']),
  75. array('value' => 'grin', 'name' => $txt['icon_grin']),
  76. array('value' => 'sad', 'name' => $txt['icon_sad']),
  77. array('value' => 'wink', 'name' => $txt['icon_wink']),
  78. array('value' => 'poll', 'name' => $txt['icon_poll']),
  79. );
  80. foreach ($icons as $k => $dummy)
  81. {
  82. $icons[$k]['url'] = $settings['images_url'] . '/post/' . $dummy['value'] . '.png';
  83. $icons[$k]['is_last'] = false;
  84. }
  85. }
  86. // Otherwise load the icons, and check we give the right image too...
  87. else
  88. {
  89. if (($temp = cache_get_data('posting_icons-' . $board_id, 480)) == null)
  90. {
  91. $request = $smcFunc['db_query']('select_message_icons', '
  92. SELECT title, filename
  93. FROM {db_prefix}message_icons
  94. WHERE id_board IN (0, {int:board_id})',
  95. array(
  96. 'board_id' => $board_id,
  97. )
  98. );
  99. $icon_data = array();
  100. while ($row = $smcFunc['db_fetch_assoc']($request))
  101. $icon_data[] = $row;
  102. $smcFunc['db_free_result']($request);
  103. $icons = array();
  104. foreach ($icon_data as $icon)
  105. {
  106. $icons[$icon['filename']] = array(
  107. 'value' => $icon['filename'],
  108. 'name' => $icon['title'],
  109. 'url' => $settings[file_exists($settings['theme_dir'] . '/images/post/' . $icon['filename'] . '.png') ? 'images_url' : 'default_images_url'] . '/post/' . $icon['filename'] . '.png',
  110. 'is_last' => false,
  111. );
  112. }
  113. cache_put_data('posting_icons-' . $board_id, $icons, 480);
  114. }
  115. else
  116. $icons = $temp;
  117. }
  118. return array_values($icons);
  119. }
  120. /**
  121. * A help function for legalise_bbc for sorting arrays based on length.
  122. * @param string $a
  123. * @param string $b
  124. * @return int 1 or -1
  125. */
  126. function sort_array_length($a, $b)
  127. {
  128. return strlen($a) < strlen($b) ? 1 : -1;
  129. }
  130. /**
  131. * Compatibility function - used in 1.1 for showing a post box.
  132. *
  133. * @param string $msg
  134. * @return string
  135. */
  136. function theme_postbox($msg)
  137. {
  138. global $context;
  139. return template_control_richedit($context['post_box_name']);
  140. }
  141. /**
  142. * Creates a box that can be used for richedit stuff like BBC, Smileys etc.
  143. * @param array $editorOptions
  144. */
  145. function create_control_richedit($editorOptions)
  146. {
  147. global $txt, $modSettings, $options, $smcFunc;
  148. global $context, $settings, $user_info, $sourcedir, $scripturl;
  149. // Load the Post language file... for the moment at least.
  150. loadLanguage('Post');
  151. // Every control must have a ID!
  152. assert(isset($editorOptions['id']));
  153. assert(isset($editorOptions['value']));
  154. // Is this the first richedit - if so we need to ensure some template stuff is initialised.
  155. if (empty($context['controls']['richedit']))
  156. {
  157. // Some general stuff.
  158. $settings['smileys_url'] = $modSettings['smileys_url'] . '/' . $user_info['smiley_set'];
  159. // This really has some WYSIWYG stuff.
  160. loadTemplate('GenericControls', isBrowser('ie') ? 'editor_ie' : 'editor');
  161. $context['html_headers'] .= '
  162. <script type="text/javascript"><!-- // --><![CDATA[
  163. var smf_smileys_url = \'' . $settings['smileys_url'] . '\';
  164. var oEditorStrings= {
  165. wont_work: \'' . addcslashes($txt['rich_edit_wont_work'], "'") . '\',
  166. func_disabled: \'' . addcslashes($txt['rich_edit_function_disabled'], "'") . '\',
  167. prompt_text_email: \'' . addcslashes($txt['prompt_text_email'], "'") . '\',
  168. prompt_text_ftp: \'' . addcslashes($txt['prompt_text_ftp'], "'") . '\',
  169. prompt_text_url: \'' . addcslashes($txt['prompt_text_url'], "'") . '\',
  170. prompt_text_img: \'' . addcslashes($txt['prompt_text_img'], "'") . '\'
  171. }
  172. // ]]></script>
  173. <script type="text/javascript" src="' . $settings['default_theme_url'] . '/scripts/editor.js?alp21"></script>
  174. <link rel="stylesheet" href="' . $settings['default_theme_url'] . '/css/jquery.sceditor.css" type="text/css" media="all" />
  175. <script type="text/javascript" src="' . $settings['default_theme_url'] . '/scripts/jquery.sceditor.js"></script>
  176. <script type="text/javascript" src="' . $settings['default_theme_url'] . '/scripts/jquery.sceditor.bbcode.js"></script>';
  177. if (!empty($txt['lang_locale']) && $txt['lang_locale'] != 'en_US')
  178. $context['html_headers'] .= '
  179. <script type="text/javascript" src="' . $scripturl . '?action=loadeditorlocale"></script>';
  180. $context['show_spellchecking'] = !empty($modSettings['enableSpellChecking']) && function_exists('pspell_new');
  181. if ($context['show_spellchecking'])
  182. {
  183. $context['html_headers'] .= '
  184. <script type="text/javascript" src="' . $settings['default_theme_url'] . '/scripts/spellcheck.js?alp21"></script>';
  185. // Some hidden information is needed in order to make the spell checking work.
  186. if (!isset($_REQUEST['xml']))
  187. $context['insert_after_template'] .= '
  188. <form name="spell_form" id="spell_form" method="post" accept-charset="' . $context['character_set'] . '" target="spellWindow" action="' . $scripturl . '?action=spellcheck">
  189. <input type="hidden" name="spellstring" value="" />
  190. </form>';
  191. }
  192. }
  193. // Start off the editor...
  194. $context['controls']['richedit'][$editorOptions['id']] = array(
  195. 'id' => $editorOptions['id'],
  196. 'value' => $editorOptions['value'],
  197. 'rich_value' => $editorOptions['value'], // 2.0 editor compatibility
  198. 'rich_active' => empty($modSettings['disable_wysiwyg']) && (!empty($options['wysiwyg_default']) || !empty($editorOptions['force_rich']) || !empty($_REQUEST[$editorOptions['id'] . '_mode'])),
  199. 'disable_smiley_box' => !empty($editorOptions['disable_smiley_box']),
  200. 'columns' => isset($editorOptions['columns']) ? $editorOptions['columns'] : 60,
  201. 'rows' => isset($editorOptions['rows']) ? $editorOptions['rows'] : 18,
  202. 'width' => isset($editorOptions['width']) ? $editorOptions['width'] : '70%',
  203. 'height' => isset($editorOptions['height']) ? $editorOptions['height'] : '250px',
  204. 'form' => isset($editorOptions['form']) ? $editorOptions['form'] : 'postmodify',
  205. 'bbc_level' => !empty($editorOptions['bbc_level']) ? $editorOptions['bbc_level'] : 'full',
  206. 'preview_type' => isset($editorOptions['preview_type']) ? (int) $editorOptions['preview_type'] : 1,
  207. 'labels' => !empty($editorOptions['labels']) ? $editorOptions['labels'] : array(),
  208. );
  209. // Switch between default images and back... mostly in case you don't have an PersonalMessage template, but do have a Post template.
  210. if (isset($settings['use_default_images']) && $settings['use_default_images'] == 'defaults' && isset($settings['default_template']))
  211. {
  212. $temp1 = $settings['theme_url'];
  213. $settings['theme_url'] = $settings['default_theme_url'];
  214. $temp2 = $settings['images_url'];
  215. $settings['images_url'] = $settings['default_images_url'];
  216. $temp3 = $settings['theme_dir'];
  217. $settings['theme_dir'] = $settings['default_theme_dir'];
  218. }
  219. if (empty($context['bbc_tags']))
  220. {
  221. // The below array makes it dead easy to add images to this control. Add it to the array and everything else is done for you!
  222. /*
  223. array(
  224. 'image' => 'bold',
  225. 'code' => 'b',
  226. 'before' => '[b]',
  227. 'after' => '[/b]',
  228. 'description' => $txt['bold'],
  229. ),
  230. */
  231. $context['bbc_tags'] = array();
  232. $context['bbc_tags'][] = array(
  233. array(
  234. 'code' => 'bold',
  235. 'description' => $txt['bold'],
  236. ),
  237. array(
  238. 'code' => 'italic',
  239. 'description' => $txt['italic'],
  240. ),
  241. array(
  242. 'code' => 'underline',
  243. 'description' => $txt['underline']
  244. ),
  245. array(
  246. 'code' => 'strike',
  247. 'description' => $txt['strike']
  248. ),
  249. array(),
  250. array(
  251. 'code' => 'pre',
  252. 'description' => $txt['preformatted']
  253. ),
  254. array(
  255. 'code' => 'left',
  256. 'description' => $txt['left_align']
  257. ),
  258. array(
  259. 'code' => 'center',
  260. 'description' => $txt['center']
  261. ),
  262. array(
  263. 'code' => 'right',
  264. 'description' => $txt['right_align']
  265. ),
  266. );
  267. $context['bbc_tags'][] = array(
  268. array(
  269. 'code' => 'flash',
  270. 'description' => $txt['flash']
  271. ),
  272. array(
  273. 'code' => 'image',
  274. 'description' => $txt['image']
  275. ),
  276. array(
  277. 'code' => 'link',
  278. 'description' => $txt['hyperlink']
  279. ),
  280. array(
  281. 'code' => 'email',
  282. 'description' => $txt['insert_email']
  283. ),
  284. array(
  285. 'code' => 'ftp',
  286. 'description' => $txt['ftp']
  287. ),
  288. array(),
  289. array(
  290. 'code' => 'glow',
  291. 'description' => $txt['glow']
  292. ),
  293. array(
  294. 'code' => 'shadow',
  295. 'description' => $txt['shadow']
  296. ),
  297. array(
  298. 'code' => 'move',
  299. 'description' => $txt['marquee']
  300. ),
  301. array(),
  302. array(
  303. 'code' => 'superscript',
  304. 'description' => $txt['superscript']
  305. ),
  306. array(
  307. 'code' => 'subscript',
  308. 'description' => $txt['subscript']
  309. ),
  310. array(
  311. 'code' => 'tt',
  312. 'description' => $txt['teletype']
  313. ),
  314. array(),
  315. array(
  316. 'code' => 'table',
  317. 'description' => $txt['table']
  318. ),
  319. array(
  320. 'code' => 'code',
  321. 'description' => $txt['bbc_code']
  322. ),
  323. array(
  324. 'code' => 'quote',
  325. 'description' => $txt['bbc_quote']
  326. ),
  327. array(),
  328. array(
  329. 'code' => 'bulletlist',
  330. 'description' => $txt['list_unordered']
  331. ),
  332. array(
  333. 'code' => 'orderedlist',
  334. 'description' => $txt['list_ordered']
  335. ),
  336. array(
  337. 'code' => 'horizontalrule',
  338. 'description' => $txt['horizontal_rule']
  339. ),
  340. );
  341. // Allow mods to modify BBC buttons.
  342. call_integration_hook('integrate_bbc_buttons');
  343. // Show the toggle?
  344. if (empty($modSettings['disable_wysiwyg']))
  345. {
  346. $context['bbc_tags'][count($context['bbc_tags']) - 1][] = array();
  347. $context['bbc_tags'][count($context['bbc_tags']) - 1][] = array(
  348. 'code' => 'unformat',
  349. 'description' => $txt['unformat_text'],
  350. );
  351. $context['bbc_tags'][count($context['bbc_tags']) - 1][] = array(
  352. 'code' => 'toggle',
  353. 'description' => $txt['toggle_view'],
  354. );
  355. }
  356. // Generate a list of buttons that shouldn't be shown - this should be the fastest way to do this.
  357. $disabled_tags = array();
  358. if (!empty($modSettings['disabledBBC']))
  359. $disabled_tags = explode(',', $modSettings['disabledBBC']);
  360. if (empty($modSettings['enableEmbeddedFlash']))
  361. $disabled_tags[] = 'flash';
  362. foreach ($disabled_tags as $tag)
  363. {
  364. if ($tag == 'list')
  365. {
  366. $context['disabled_tags']['bulletlist'] = true;
  367. $context['disabled_tags']['orderedlist'] = true;
  368. }
  369. elseif ($tag == 'b')
  370. $context['disabled_tags']['bold'] = true;
  371. elseif ($tag == 'i')
  372. $context['disabled_tags']['italic'] = true;
  373. elseif ($tag == 'i')
  374. $context['disabled_tags']['underline'] = true;
  375. elseif ($tag == 'i')
  376. $context['disabled_tags']['strike'] = true;
  377. elseif ($tag == 'img')
  378. $context['disabled_tags']['image'] = true;
  379. elseif ($tag == 'url')
  380. $context['disabled_tags']['link'] = true;
  381. elseif ($tag == 'sup')
  382. $context['disabled_tags']['superscript'] = true;
  383. elseif ($tag == 'sub')
  384. $context['disabled_tags']['subscript'] = true;
  385. elseif ($tag == 'hr')
  386. $context['disabled_tags']['horizontalrule'] = true;
  387. $context['disabled_tags'][trim($tag)] = true;
  388. }
  389. $bbcodes_styles = '';
  390. $context['bbcodes_hanlders'] = '';
  391. $context['bbc_toolbar'] = array();
  392. foreach ($context['bbc_tags'] as $row => $tagRow)
  393. {
  394. if (!isset($context['bbc_toolbar'][$row]))
  395. $context['bbc_toolbar'][$row] = array();
  396. $tagsRow = array();
  397. foreach ($tagRow as $tag)
  398. {
  399. if (!empty($tag))
  400. {
  401. if (empty($context['disabled_tags'][$tag['code']]))
  402. {
  403. $tagsRow[] = $tag['code'];
  404. if (isset($tag['image']))
  405. $bbcodes_styles .= '
  406. .sceditor-button-' . $tag['code'] . ' div {
  407. background: url(\'' . $settings['default_theme_url'] . '/images/bbc/' . $tag['image'] . '.png\');
  408. }';
  409. if (isset($tag['before']))
  410. {
  411. $context['bbcodes_hanlders'] = '
  412. $.sceditor.setCommand(
  413. ' . javaScriptEscape($tag['code']) . ',
  414. function () {
  415. this.wysiwygEditorInsertHtml(' . javaScriptEscape($tag['before']) . (isset($tag['after']) ? ', ' . javaScriptEscape($tag['after']) : '') . ');
  416. },
  417. ' . javaScriptEscape($tag['description']) . ',
  418. null,
  419. [' . javaScriptEscape($tag['before']) . (isset($tag['after']) ? ', ' . javaScriptEscape($tag['after']) : '') . ']
  420. );';
  421. }
  422. }
  423. }
  424. else
  425. {
  426. $context['bbc_toolbar'][$row][] = implode(',', $tagsRow);
  427. $tagsRow = array();
  428. }
  429. }
  430. if ($row == 0)
  431. {
  432. $context['bbc_toolbar'][$row][] = implode(',', $tagsRow);
  433. $tagsRow = array();
  434. if (!isset($context['disabled_tags']['font']))
  435. $tagsRow[] = 'font';
  436. if (!isset($context['disabled_tags']['size']))
  437. $tagsRow[] = 'size';
  438. if (!isset($context['disabled_tags']['color']))
  439. $tagsRow[] = 'color';
  440. }
  441. elseif ($row == 1 && empty($modSettings['disable_wysiwyg']))
  442. {
  443. $tmp = array();
  444. $tagsRow[] = 'removeformat';
  445. $tagsRow[] = 'source';
  446. if (!empty($tmp))
  447. {
  448. $tagsRow[] = '|' . implode(',', $tmp);
  449. }
  450. }
  451. if (!empty($tagsRow))
  452. $context['bbc_toolbar'][$row][] = implode(',', $tagsRow);
  453. }
  454. if (!empty($bbcodes_styles))
  455. $context['html_headers'] .= '
  456. <style type="text/css">' . $bbcodes_styles . '
  457. </style>';
  458. }
  459. // Initialize smiley array... if not loaded before.
  460. if (empty($context['smileys']) && empty($editorOptions['disable_smiley_box']))
  461. {
  462. $context['smileys'] = array(
  463. 'postform' => array(),
  464. 'popup' => array(),
  465. );
  466. // Load smileys - don't bother to run a query if we're not using the database's ones anyhow.
  467. if (empty($modSettings['smiley_enable']) && $user_info['smiley_set'] != 'none')
  468. $context['smileys']['postform'][] = array(
  469. 'smileys' => array(
  470. array(
  471. 'code' => ':)',
  472. 'filename' => 'smiley.gif',
  473. 'description' => $txt['icon_smiley'],
  474. ),
  475. array(
  476. 'code' => ';)',
  477. 'filename' => 'wink.gif',
  478. 'description' => $txt['icon_wink'],
  479. ),
  480. array(
  481. 'code' => ':D',
  482. 'filename' => 'cheesy.gif',
  483. 'description' => $txt['icon_cheesy'],
  484. ),
  485. array(
  486. 'code' => ';D',
  487. 'filename' => 'grin.gif',
  488. 'description' => $txt['icon_grin']
  489. ),
  490. array(
  491. 'code' => '>:(',
  492. 'filename' => 'angry.gif',
  493. 'description' => $txt['icon_angry'],
  494. ),
  495. array(
  496. 'code' => ':(',
  497. 'filename' => 'sad.gif',
  498. 'description' => $txt['icon_sad'],
  499. ),
  500. array(
  501. 'code' => ':o',
  502. 'filename' => 'shocked.gif',
  503. 'description' => $txt['icon_shocked'],
  504. ),
  505. array(
  506. 'code' => '8)',
  507. 'filename' => 'cool.gif',
  508. 'description' => $txt['icon_cool'],
  509. ),
  510. array(
  511. 'code' => '???',
  512. 'filename' => 'huh.gif',
  513. 'description' => $txt['icon_huh'],
  514. ),
  515. array(
  516. 'code' => '::)',
  517. 'filename' => 'rolleyes.gif',
  518. 'description' => $txt['icon_rolleyes'],
  519. ),
  520. array(
  521. 'code' => ':P',
  522. 'filename' => 'tongue.gif',
  523. 'description' => $txt['icon_tongue'],
  524. ),
  525. array(
  526. 'code' => ':-[',
  527. 'filename' => 'embarrassed.gif',
  528. 'description' => $txt['icon_embarrassed'],
  529. ),
  530. array(
  531. 'code' => ':-X',
  532. 'filename' => 'lipsrsealed.gif',
  533. 'description' => $txt['icon_lips'],
  534. ),
  535. array(
  536. 'code' => ':-\\',
  537. 'filename' => 'undecided.gif',
  538. 'description' => $txt['icon_undecided'],
  539. ),
  540. array(
  541. 'code' => ':-*',
  542. 'filename' => 'kiss.gif',
  543. 'description' => $txt['icon_kiss'],
  544. ),
  545. array(
  546. 'code' => ':\'(',
  547. 'filename' => 'cry.gif',
  548. 'description' => $txt['icon_cry'],
  549. 'isLast' => true,
  550. ),
  551. ),
  552. 'isLast' => true,
  553. );
  554. elseif ($user_info['smiley_set'] != 'none')
  555. {
  556. if (($temp = cache_get_data('posting_smileys', 480)) == null)
  557. {
  558. $request = $smcFunc['db_query']('', '
  559. SELECT code, filename, description, smiley_row, hidden
  560. FROM {db_prefix}smileys
  561. WHERE hidden IN (0, 2)
  562. ORDER BY smiley_row, smiley_order',
  563. array(
  564. )
  565. );
  566. while ($row = $smcFunc['db_fetch_assoc']($request))
  567. {
  568. $row['filename'] = htmlspecialchars($row['filename']);
  569. $row['description'] = htmlspecialchars($row['description']);
  570. $context['smileys'][empty($row['hidden']) ? 'postform' : 'popup'][$row['smiley_row']]['smileys'][] = $row;
  571. }
  572. $smcFunc['db_free_result']($request);
  573. foreach ($context['smileys'] as $section => $smileyRows)
  574. {
  575. foreach ($smileyRows as $rowIndex => $smileys)
  576. $context['smileys'][$section][$rowIndex]['smileys'][count($smileys['smileys']) - 1]['isLast'] = true;
  577. if (!empty($smileyRows))
  578. $context['smileys'][$section][count($smileyRows) - 1]['isLast'] = true;
  579. }
  580. cache_put_data('posting_smileys', $context['smileys'], 480);
  581. }
  582. else
  583. $context['smileys'] = $temp;
  584. }
  585. }
  586. // Set a flag so the sub template knows what to do...
  587. $context['show_bbc'] = !empty($modSettings['enableBBC']) && !empty($settings['show_bbc']);
  588. // Switch the URLs back... now we're back to whatever the main sub template is. (like folder in PersonalMessage.)
  589. if (isset($settings['use_default_images']) && $settings['use_default_images'] == 'defaults' && isset($settings['default_template']))
  590. {
  591. $settings['theme_url'] = $temp1;
  592. $settings['images_url'] = $temp2;
  593. $settings['theme_dir'] = $temp3;
  594. }
  595. }
  596. /**
  597. * Create a anti-bot verification control?
  598. * @param array &$verificationOptions
  599. * @param bool $do_test = false
  600. */
  601. function create_control_verification(&$verificationOptions, $do_test = false)
  602. {
  603. global $txt, $modSettings, $options, $smcFunc;
  604. global $context, $settings, $user_info, $sourcedir, $scripturl;
  605. // First verification means we need to set up some bits...
  606. if (empty($context['controls']['verification']))
  607. {
  608. // The template
  609. loadTemplate('GenericControls');
  610. // Some javascript ma'am?
  611. if (!empty($verificationOptions['override_visual']) || (!empty($modSettings['visual_verification_type']) && !isset($verificationOptions['override_visual'])))
  612. $context['html_headers'] .= '
  613. <script type="text/javascript" src="' . $settings['default_theme_url'] . '/scripts/captcha.js"></script>';
  614. $context['use_graphic_library'] = in_array('gd', get_loaded_extensions());
  615. // Skip I, J, L, O, Q, S and Z.
  616. $context['standard_captcha_range'] = array_merge(range('A', 'H'), array('K', 'M', 'N', 'P', 'R'), range('T', 'Y'));
  617. }
  618. // Always have an ID.
  619. assert(isset($verificationOptions['id']));
  620. $isNew = !isset($context['controls']['verification'][$verificationOptions['id']]);
  621. // Log this into our collection.
  622. if ($isNew)
  623. $context['controls']['verification'][$verificationOptions['id']] = array(
  624. 'id' => $verificationOptions['id'],
  625. 'show_visual' => !empty($verificationOptions['override_visual']) || (!empty($modSettings['visual_verification_type']) && !isset($verificationOptions['override_visual'])),
  626. 'number_questions' => isset($verificationOptions['override_qs']) ? $verificationOptions['override_qs'] : (!empty($modSettings['qa_verification_number']) ? $modSettings['qa_verification_number'] : 0),
  627. 'max_errors' => isset($verificationOptions['max_errors']) ? $verificationOptions['max_errors'] : 3,
  628. 'image_href' => $scripturl . '?action=verificationcode;vid=' . $verificationOptions['id'] . ';rand=' . md5(mt_rand()),
  629. 'text_value' => '',
  630. 'questions' => array(),
  631. );
  632. $thisVerification = &$context['controls']['verification'][$verificationOptions['id']];
  633. // Add javascript for the object.
  634. if ($context['controls']['verification'][$verificationOptions['id']]['show_visual'] && !WIRELESS)
  635. $context['insert_after_template'] .= '
  636. <script type="text/javascript"><!-- // --><![CDATA[
  637. var verification' . $verificationOptions['id'] . 'Handle = new smfCaptcha("' . $thisVerification['image_href'] . '", "' . $verificationOptions['id'] . '", ' . ($context['use_graphic_library'] ? 1 : 0) . ');
  638. // ]]></script>';
  639. // Is there actually going to be anything?
  640. if (empty($thisVerification['show_visual']) && empty($thisVerification['number_questions']))
  641. return false;
  642. elseif (!$isNew && !$do_test)
  643. return true;
  644. // If we want questions do we have a cache of all the IDs?
  645. if (!empty($thisVerification['number_questions']) && empty($modSettings['question_id_cache']))
  646. {
  647. if (($modSettings['question_id_cache'] = cache_get_data('verificationQuestionIds', 300)) == null)
  648. {
  649. $request = $smcFunc['db_query']('', '
  650. SELECT id_comment
  651. FROM {db_prefix}log_comments
  652. WHERE comment_type = {string:ver_test}',
  653. array(
  654. 'ver_test' => 'ver_test',
  655. )
  656. );
  657. $modSettings['question_id_cache'] = array();
  658. while ($row = $smcFunc['db_fetch_assoc']($request))
  659. $modSettings['question_id_cache'][] = $row['id_comment'];
  660. $smcFunc['db_free_result']($request);
  661. if (!empty($modSettings['cache_enable']))
  662. cache_put_data('verificationQuestionIds', $modSettings['question_id_cache'], 300);
  663. }
  664. }
  665. if (!isset($_SESSION[$verificationOptions['id'] . '_vv']))
  666. $_SESSION[$verificationOptions['id'] . '_vv'] = array();
  667. // Do we need to refresh the verification?
  668. if (!$do_test && (!empty($_SESSION[$verificationOptions['id'] . '_vv']['did_pass']) || empty($_SESSION[$verificationOptions['id'] . '_vv']['count']) || $_SESSION[$verificationOptions['id'] . '_vv']['count'] > 3) && empty($verificationOptions['dont_refresh']))
  669. $force_refresh = true;
  670. else
  671. $force_refresh = false;
  672. // This can also force a fresh, although unlikely.
  673. if (($thisVerification['show_visual'] && empty($_SESSION[$verificationOptions['id'] . '_vv']['code'])) || ($thisVerification['number_questions'] && empty($_SESSION[$verificationOptions['id'] . '_vv']['q'])))
  674. $force_refresh = true;
  675. $verification_errors = array();
  676. // Start with any testing.
  677. if ($do_test)
  678. {
  679. // This cannot happen!
  680. if (!isset($_SESSION[$verificationOptions['id'] . '_vv']['count']))
  681. fatal_lang_error('no_access', false);
  682. // ... nor this!
  683. if ($thisVerification['number_questions'] && (!isset($_SESSION[$verificationOptions['id'] . '_vv']['q']) || !isset($_REQUEST[$verificationOptions['id'] . '_vv']['q'])))
  684. fatal_lang_error('no_access', false);
  685. if ($thisVerification['show_visual'] && (empty($_REQUEST[$verificationOptions['id'] . '_vv']['code']) || empty($_SESSION[$verificationOptions['id'] . '_vv']['code']) || strtoupper($_REQUEST[$verificationOptions['id'] . '_vv']['code']) !== $_SESSION[$verificationOptions['id'] . '_vv']['code']))
  686. $verification_errors[] = 'wrong_verification_code';
  687. if ($thisVerification['number_questions'])
  688. {
  689. // Get the answers and see if they are all right!
  690. $request = $smcFunc['db_query']('', '
  691. SELECT id_comment, recipient_name AS answer
  692. FROM {db_prefix}log_comments
  693. WHERE comment_type = {string:ver_test}
  694. AND id_comment IN ({array_int:comment_ids})',
  695. array(
  696. 'ver_test' => 'ver_test',
  697. 'comment_ids' => $_SESSION[$verificationOptions['id'] . '_vv']['q'],
  698. )
  699. );
  700. $incorrectQuestions = array();
  701. while ($row = $smcFunc['db_fetch_assoc']($request))
  702. {
  703. if (!isset($_REQUEST[$verificationOptions['id'] . '_vv']['q'][$row['id_comment']]) || trim($_REQUEST[$verificationOptions['id'] . '_vv']['q'][$row['id_comment']]) == '' || trim($smcFunc['htmlspecialchars'](strtolower($_REQUEST[$verificationOptions['id'] . '_vv']['q'][$row['id_comment']]))) != strtolower($row['answer']))
  704. $incorrectQuestions[] = $row['id_comment'];
  705. }
  706. $smcFunc['db_free_result']($request);
  707. if (!empty($incorrectQuestions))
  708. $verification_errors[] = 'wrong_verification_answer';
  709. }
  710. }
  711. // Any errors means we refresh potentially.
  712. if (!empty($verification_errors))
  713. {
  714. if (empty($_SESSION[$verificationOptions['id'] . '_vv']['errors']))
  715. $_SESSION[$verificationOptions['id'] . '_vv']['errors'] = 0;
  716. // Too many errors?
  717. elseif ($_SESSION[$verificationOptions['id'] . '_vv']['errors'] > $thisVerification['max_errors'])
  718. $force_refresh = true;
  719. // Keep a track of these.
  720. $_SESSION[$verificationOptions['id'] . '_vv']['errors']++;
  721. }
  722. // Are we refreshing then?
  723. if ($force_refresh)
  724. {
  725. // Assume nothing went before.
  726. $_SESSION[$verificationOptions['id'] . '_vv']['count'] = 0;
  727. $_SESSION[$verificationOptions['id'] . '_vv']['errors'] = 0;
  728. $_SESSION[$verificationOptions['id'] . '_vv']['did_pass'] = false;
  729. $_SESSION[$verificationOptions['id'] . '_vv']['q'] = array();
  730. $_SESSION[$verificationOptions['id'] . '_vv']['code'] = '';
  731. // Generating a new image.
  732. if ($thisVerification['show_visual'])
  733. {
  734. // Are we overriding the range?
  735. $character_range = !empty($verificationOptions['override_range']) ? $verificationOptions['override_range'] : $context['standard_captcha_range'];
  736. for ($i = 0; $i < 6; $i++)
  737. $_SESSION[$verificationOptions['id'] . '_vv']['code'] .= $character_range[array_rand($character_range)];
  738. }
  739. // Getting some new questions?
  740. if ($thisVerification['number_questions'])
  741. {
  742. // Pick some random IDs
  743. $questionIDs = array();
  744. if ($thisVerification['number_questions'] == 1)
  745. $questionIDs[] = $modSettings['question_id_cache'][array_rand($modSettings['question_id_cache'], $thisVerification['number_questions'])];
  746. else
  747. foreach (array_rand($modSettings['question_id_cache'], $thisVerification['number_questions']) as $index)
  748. $questionIDs[] = $modSettings['question_id_cache'][$index];
  749. }
  750. }
  751. else
  752. {
  753. // Same questions as before.
  754. $questionIDs = !empty($_SESSION[$verificationOptions['id'] . '_vv']['q']) ? $_SESSION[$verificationOptions['id'] . '_vv']['q'] : array();
  755. $thisVerification['text_value'] = !empty($_REQUEST[$verificationOptions['id'] . '_vv']['code']) ? $smcFunc['htmlspecialchars']($_REQUEST[$verificationOptions['id'] . '_vv']['code']) : '';
  756. }
  757. // Have we got some questions to load?
  758. if (!empty($questionIDs))
  759. {
  760. $request = $smcFunc['db_query']('', '
  761. SELECT id_comment, body AS question
  762. FROM {db_prefix}log_comments
  763. WHERE comment_type = {string:ver_test}
  764. AND id_comment IN ({array_int:comment_ids})',
  765. array(
  766. 'ver_test' => 'ver_test',
  767. 'comment_ids' => $questionIDs,
  768. )
  769. );
  770. $_SESSION[$verificationOptions['id'] . '_vv']['q'] = array();
  771. while ($row = $smcFunc['db_fetch_assoc']($request))
  772. {
  773. $thisVerification['questions'][] = array(
  774. 'id' => $row['id_comment'],
  775. 'q' => parse_bbc($row['question']),
  776. 'is_error' => !empty($incorrectQuestions) && in_array($row['id_comment'], $incorrectQuestions),
  777. // Remember a previous submission?
  778. 'a' => isset($_REQUEST[$verificationOptions['id'] . '_vv'], $_REQUEST[$verificationOptions['id'] . '_vv']['q'], $_REQUEST[$verificationOptions['id'] . '_vv']['q'][$row['id_comment']]) ? $smcFunc['htmlspecialchars']($_REQUEST[$verificationOptions['id'] . '_vv']['q'][$row['id_comment']]) : '',
  779. );
  780. $_SESSION[$verificationOptions['id'] . '_vv']['q'][] = $row['id_comment'];
  781. }
  782. $smcFunc['db_free_result']($request);
  783. }
  784. $_SESSION[$verificationOptions['id'] . '_vv']['count'] = empty($_SESSION[$verificationOptions['id'] . '_vv']['count']) ? 1 : $_SESSION[$verificationOptions['id'] . '_vv']['count'] + 1;
  785. // Return errors if we have them.
  786. if (!empty($verification_errors))
  787. return $verification_errors;
  788. // If we had a test that one, make a note.
  789. elseif ($do_test)
  790. $_SESSION[$verificationOptions['id'] . '_vv']['did_pass'] = true;
  791. // Say that everything went well chaps.
  792. return true;
  793. }
  794. /**
  795. * This keeps track of all registered handling functions for auto suggest functionality and passes execution to them.
  796. * @param bool $checkRegistered = null
  797. */
  798. function AutoSuggestHandler($checkRegistered = null)
  799. {
  800. global $context;
  801. // These are all registered types.
  802. $searchTypes = array(
  803. 'member' => 'Member',
  804. 'versions' => 'SMFVersions',
  805. );
  806. // If we're just checking the callback function is registered return true or false.
  807. if ($checkRegistered != null)
  808. return isset($searchTypes[$checkRegistered]) && function_exists('AutoSuggest_Search_' . $checkRegistered);
  809. checkSession('get');
  810. loadTemplate('Xml');
  811. // Any parameters?
  812. $context['search_param'] = isset($_REQUEST['search_param']) ? unserialize(base64_decode($_REQUEST['search_param'])) : array();
  813. if (isset($_REQUEST['suggest_type'], $_REQUEST['search']) && isset($searchTypes[$_REQUEST['suggest_type']]))
  814. {
  815. $function = 'AutoSuggest_Search_' . $searchTypes[$_REQUEST['suggest_type']];
  816. $context['sub_template'] = 'generic_xml';
  817. $context['xml_data'] = $function();
  818. }
  819. }
  820. /**
  821. * Search for a member - by real_name or member_name by default.
  822. *
  823. * @return string
  824. */
  825. function AutoSuggest_Search_Member()
  826. {
  827. global $user_info, $txt, $smcFunc, $context;
  828. $_REQUEST['search'] = trim($smcFunc['strtolower']($_REQUEST['search'])) . '*';
  829. $_REQUEST['search'] = strtr($_REQUEST['search'], array('%' => '\%', '_' => '\_', '*' => '%', '?' => '_', '&#038;' => '&amp;'));
  830. // Find the member.
  831. $request = $smcFunc['db_query']('', '
  832. SELECT id_member, real_name
  833. FROM {db_prefix}members
  834. WHERE real_name LIKE {string:search}' . (!empty($context['search_param']['buddies']) ? '
  835. AND id_member IN ({array_int:buddy_list})' : '') . '
  836. AND is_activated IN (1, 11)
  837. LIMIT ' . ($smcFunc['strlen']($_REQUEST['search']) <= 2 ? '100' : '800'),
  838. array(
  839. 'buddy_list' => $user_info['buddies'],
  840. 'search' => $_REQUEST['search'],
  841. )
  842. );
  843. $xml_data = array(
  844. 'items' => array(
  845. 'identifier' => 'item',
  846. 'children' => array(),
  847. ),
  848. );
  849. while ($row = $smcFunc['db_fetch_assoc']($request))
  850. {
  851. $row['real_name'] = strtr($row['real_name'], array('&amp;' => '&#038;', '&lt;' => '&#060;', '&gt;' => '&#062;', '&quot;' => '&#034;'));
  852. $xml_data['items']['children'][] = array(
  853. 'attributes' => array(
  854. 'id' => $row['id_member'],
  855. ),
  856. 'value' => $row['real_name'],
  857. );
  858. }
  859. $smcFunc['db_free_result']($request);
  860. return $xml_data;
  861. }
  862. function AutoSuggest_Search_SMFVersions()
  863. {
  864. $xml_data = array(
  865. 'items' => array(
  866. 'identifier' => 'item',
  867. 'children' => array(),
  868. ),
  869. );
  870. $versions = array(
  871. 'SMF 1.1',
  872. 'SMF 1.1.1',
  873. 'SMF 1.1.2',
  874. 'SMF 1.1.3',
  875. 'SMF 1.1.4',
  876. 'SMF 1.1.5',
  877. 'SMF 1.1.6',
  878. 'SMF 1.1.7',
  879. 'SMF 1.1.8',
  880. 'SMF 1.1.9',
  881. 'SMF 1.1.10',
  882. 'SMF 1.1.11',
  883. 'SMF 1.1.12',
  884. 'SMF 1.1.13',
  885. 'SMF 1.1.14',
  886. 'SMF 1.1.15',
  887. 'SMF 1.1.16',
  888. 'SMF 2.0 beta 1',
  889. 'SMF 2.0 beta 1.2',
  890. 'SMF 2.0 beta 2',
  891. 'SMF 2.0 beta 3',
  892. 'SMF 2.0 RC 1',
  893. 'SMF 2.0 RC 1.2',
  894. 'SMF 2.0 RC 2',
  895. 'SMF 2.0 RC 3',
  896. 'SMF 2.0',
  897. 'SMF 2.0.1',
  898. 'SMF 2.0.2',
  899. );
  900. foreach ($versions as $id => $version)
  901. if (strpos($version, strtoupper($_REQUEST['search'])) !== false)
  902. $xml_data['items']['children'][] = array(
  903. 'attributes' => array(
  904. 'id' => $id,
  905. ),
  906. 'value' => $version,
  907. );
  908. return $xml_data;
  909. }
  910. ?>