· 9 years ago · Oct 20, 2016, 03:40 PM
1<?php
2/* by Tomasz 'Devilshakerz' Mlynski [devilshakerz.com]; Copyright (C) 2014-2016
3 released under Creative Commons BY-NC-SA 4.0 license: https://creativecommons.org/licenses/by-nc-sa/4.0/ */
4
5$plugins->add_hook('global_start', ['dvz_shoutbox', 'global_start']); // cache shoutbox templates
6$plugins->add_hook('global_end', ['dvz_shoutbox', 'global_end']); // catch archive page
7$plugins->add_hook('xmlhttp', ['dvz_shoutbox', 'xmlhttp']); // xmlhttp.php listening
8$plugins->add_hook('index_end', ['dvz_shoutbox', 'load_window']); // load Shoutbox window to {$dvz_shoutbox} variable
9
10$plugins->add_hook('admin_config_settings_change', ['dvz_shoutbox', 'admin_config_settings_change']);
11$plugins->add_hook('admin_user_users_merge_commit', ['dvz_shoutbox', 'user_merge']);
12
13$plugins->add_hook('fetch_wol_activity_end', ['dvz_shoutbox', 'activity']); // catch activity
14$plugins->add_hook('build_friendly_wol_location_end', ['dvz_shoutbox', 'activity_translate']); // translate activity
15
16$plugins->add_hook('misc_clearcookies', ['dvz_shoutbox', 'clearcookies']);
17
18function dvz_shoutbox_info()
19{
20 return [
21 'name' => 'DVZ Shoutbox - Custom',
22 'description' => 'Lightweight AJAX chat.',
23 'website' => 'https://devilshakerz.com/',
24 'author' => 'Tomasz \'Devilshakerz\' Mlynski',
25 'authorsite' => 'https://devilshakerz.com/',
26 'version' => '2.3.1 - 1.0',
27 'codename' => 'dvz_shoutbox',
28 'compatibility' => '18*',
29 ];
30}
31
32function dvz_shoutbox_install()
33{
34 global $mybb, $db;
35
36 $mybb->binary_fields['dvz_shoutbox'] = ['ipaddress' => true];
37
38 // table
39 switch ($db->type) {
40 case 'pgsql':
41 $db->write_query("
42 CREATE TABLE IF NOT EXISTS " . TABLE_PREFIX . "dvz_shoutbox (
43 id serial,
44 uid int NOT NULL,
45 text text NULL,
46 date int NOT NULL,
47 modified int NULL DEFAULT NULL,
48 ipaddress bytea NOT NULL,
49 PRIMARY KEY (id)
50 )
51 ");
52 break;
53 case 'sqlite':
54 $db->write_query("
55 CREATE TABLE IF NOT EXISTS " . TABLE_PREFIX . "dvz_shoutbox (
56 id integer primary key,
57 uid integer NOT NULL,
58 text text NULL,
59 date integer NOT NULL,
60 modified integer NULL DEFAULT NULL,
61 ipaddress bytea NOT NULL
62 )
63 ");
64 break;
65 default:
66 $query = $db->query("SELECT SUPPORT FROM INFORMATION_SCHEMA.ENGINES WHERE ENGINE = 'InnoDB'");
67 $innodbSupport = $db->num_rows($query) && in_array($db->fetch_field($query, 'SUPPORT'), ['DEFAULT', 'YES']);
68
69 $db->write_query("
70 CREATE TABLE IF NOT EXISTS `" . TABLE_PREFIX . "dvz_shoutbox` (
71 `id` int(11) NOT NULL auto_increment,
72 `uid` int(11) NOT NULL,
73 `text` text NULL,
74 `date` int(11) NOT NULL,
75 `modified` int(11) NULL DEFAULT NULL,
76 `ipaddress` varbinary(16) NOT NULL,
77 PRIMARY KEY (`id`)
78 ) " . ($innodbSupport ? "ENGINE=InnoDB" : null) . " " . $db->build_create_table_collation() . "
79 ");
80
81 if(!$db->table_exists('dvz_reports'))
82 {
83 $db->write_query("CREATE TABLE `".TABLE_PREFIX."dvz_reports` (
84 `id` int(11) NOT NULL,
85 `shid` int(11) NOT NULL,
86 `uid` int(11) NOT NULL,
87 `reason` varchar(150) NOT NULL,
88 `date` int(11) NOT NULL,
89 `ip` varchar(20) NOT NULL,
90 PRIMARY KEY (`id`)
91 ) ENGINE=MyISAM".$db->build_create_table_collation());
92 }
93 break;
94 }
95
96 // example shout
97 $db->insert_query('dvz_shoutbox', [
98 'uid' => 1,
99 'text' => 'DVZ Shoutbox!',
100 'date' => TIME_NOW,
101 'ipaddress' => $db->escape_binary( my_inet_pton('127.0.0.1') ),
102 ]);
103
104 // settings
105 $settingGroupId = $db->insert_query('settinggroups', [
106 'name' => 'dvz_shoutbox',
107 'title' => 'DVZ Shoutbox',
108 'description' => 'Settings for DVZ Shoutbox.',
109 ]);
110
111 $settings = [
112 [
113 'name' => 'dvz_sb_num',
114 'title' => 'Shouts to display',
115 'description' => 'Number of shouts to be displayed in the Shoutbox window.',
116 'optionscode' => 'numeric',
117 'value' => '20',
118 ],
119 [
120 'name' => 'dvz_sb_num_archive',
121 'title' => 'Shouts to display on archive',
122 'description' => 'Number of shouts to be displayed per page on Archive view.',
123 'optionscode' => 'numeric',
124 'value' => '20',
125 ],
126 [
127 'name' => 'dvz_sb_reversed',
128 'title' => 'Reversed order',
129 'description' => 'Reverses the shouts display order in the Shoutbox window so that new ones appear on the bottom. You may also want to move the <b>{$panel}</b> variable below the window in the <i>dvz_shoutbox</i> template.',
130 'optionscode' => 'yesno',
131 'value' => '0',
132 ],
133 [
134 'name' => 'dvz_sb_height',
135 'title' => 'Shoutbox height',
136 'description' => 'Height of the Shoutbox window in pixels.',
137 'optionscode' => 'numeric',
138 'value' => '160',
139 ],
140 [
141 'name' => 'dvz_sb_dateformat',
142 'title' => 'Date format',
143 'description' => 'Format of the date displayed. This format uses the PHP\'s <a href="https://secure.php.net/manual/en/function.date.php#refsect1-function.date-parameters">date() function syntax</a>.',
144 'optionscode' => 'text',
145 'value' => 'd M H:i',
146 ],
147 [
148 'name' => 'dvz_sb_maxlength',
149 'title' => 'Maximum message length',
150 'description' => 'Set 0 to disable the limit.',
151 'optionscode' => 'numeric',
152 'value' => '0',
153 ],
154 [
155 'name' => 'dvz_sb_mycode',
156 'title' => 'Parse MyCode',
157 'description' => '',
158 'optionscode' => 'yesno',
159 'value' => '1',
160 ],
161 [
162 'name' => 'dvz_sb_smilies',
163 'title' => 'Parse smilies',
164 'description' => '',
165 'optionscode' => 'yesno',
166 'value' => '1',
167 ],
168 [
169 'name' => 'dvz_sb_interval',
170 'title' => 'Refresh interval',
171 'description' => 'Number of seconds between Shoutbox updates (lower values provide better synchronization but cause higher server load). Set 0 to disable the auto-refreshing feature.',
172 'optionscode' => 'numeric',
173 'value' => '5',
174 ],
175 [
176 'name' => 'dvz_sb_away',
177 'title' => 'Away mode',
178 'description' => 'Number of seconds after last user action (e.g. click) after which shoutbox will be minimized to prevent unnecessary usage of server resources. Set 0 to disable this feature.',
179 'optionscode' => 'numeric',
180 'value' => '600',
181 ],
182 [
183 'name' => 'dvz_sb_antiflood',
184 'title' => 'Anti-flood interval',
185 'description' => 'Forces a minimum number of seconds to last between user\'s shouts (this does not apply to Shoutbox moderators).',
186 'optionscode' => 'numeric',
187 'value' => '5',
188 ],
189 [
190 'name' => 'dvz_sb_sync',
191 'title' => 'Moderation synchronization',
192 'description' => 'Applies moderation actions without refreshing the Shoutbox window page.',
193 'optionscode' => 'onoff',
194 'value' => '1',
195 ],
196 [
197 'name' => 'dvz_sb_mark_unread',
198 'title' => 'Mark unread messages',
199 'description' => 'Marks messages that appeared after user\'s last visit.',
200 'optionscode' => 'onoff',
201 'value' => '1',
202 ],
203 [
204 'name' => 'dvz_sb_lazyload',
205 'title' => 'Lazy load',
206 'description' => 'Start loading data only when the Shoutbox window is actually being displayed on the screen (the page is scrolled to the Shoutbox position).',
207 'optionscode' => 'select
208off=Disabled
209start=Check if on display to start
210always=Always check if on display to refresh',
211 'value' => 'off',
212 ],
213 [
214 'name' => 'dvz_sb_status',
215 'title' => 'Shoutbox default status',
216 'description' => 'Choose whether Shoutbox window should be expanded or collapsed by default.',
217 'optionscode' => 'onoff',
218 'value' => '1',
219 ],
220 [
221 'name' => 'dvz_sb_minposts',
222 'title' => 'Minimum posts required to shout',
223 'description' => 'Set 0 to allow everyone.',
224 'optionscode' => 'numeric',
225 'value' => '0',
226 ],
227 [
228 'name' => 'dvz_sb_groups_view',
229 'title' => 'Group permissions: View',
230 'description' => 'User groups that can view Shoutbox.',
231 'optionscode' => 'groupselect',
232 'value' => '-1',
233 ],
234 [
235 'name' => 'dvz_sb_groups_refresh',
236 'title' => 'Group permissions: Auto-refresh',
237 'description' => 'User groups that shoutbox will be refreshing for.',
238 'optionscode' => 'groupselect',
239 'value' => '-1',
240 ],
241 [
242 'name' => 'dvz_sb_groups_shout',
243 'title' => 'Group permissions: Shout',
244 'description' => 'User groups that can post shouts in Shoutbox (logged in users only).',
245 'optionscode' => 'groupselect',
246 'value' => '-1',
247 ],
248 [
249 'name' => 'dvz_sb_groups_recall',
250 'title' => 'Group permissions: Scroll back to show past shouts',
251 'description' => 'User groups that shoutbox will load previous posts when scrolling back for.',
252 'optionscode' => 'groupselect',
253 'value' => '-1',
254 ],
255 [
256 'name' => 'dvz_sb_groups_mod',
257 'title' => 'Group permissions: Moderation',
258 'description' => 'User groups that can moderate the Shoutbox (edit and delete shouts).',
259 'optionscode' => 'groupselect',
260 'value' => '',
261 ],
262 [
263 'name' => 'dvz_sb_groups_mod_own',
264 'title' => 'Group permissions: Moderation of own shouts',
265 'description' => 'Users groups whose members can edit and delete their own shouts.',
266 'optionscode' => 'groupselect',
267 'value' => '',
268 ],
269 [
270 'name' => 'dvz_sb_supermods',
271 'title' => 'Super moderators are Shoutbox moderators',
272 'description' => 'Automatically allow forum super moderators to moderate Shoutbox as well.',
273 'optionscode' => 'yesno',
274 'value' => '1',
275 ],
276 [
277 'name' => 'dvz_sb_blocked_users',
278 'title' => 'Banned users',
279 'description' => 'Comma-separated list of user IDs that are banned from posting messages.',
280 'optionscode' => 'textarea',
281 'value' => '',
282 ],
283 ];
284
285 $i = 1;
286
287 foreach ($settings as &$row) {
288 $row['gid'] = $settingGroupId;
289 $row['title'] = $db->escape_string($row['title']);
290 $row['description'] = $db->escape_string($row['description']);
291 $row['disporder'] = $i++;
292 }
293
294 $db->insert_query_multiple('settings', $settings);
295
296 rebuild_settings();
297
298 // templates
299 $templates = [
300 'dvz_shoutbox_panel' => '<div class="panel">
301<form>
302<input type="text" class="text" placeholder="{$lang->dvz_sb_default}" maxlength="{$maxlength}" autocomplete="off" />
303<input type="submit" style="display:none" />
304</form>
305</div>',
306
307 'dvz_shoutbox' => '<div id="shoutbox" class="front{$classes}">
308
309<div class="head">
310<strong>{$lang->dvz_sb_shoutbox}</strong>
311<p class="right"><a href="{$mybb->settings[\'bburl\']}/index.php?action=shoutbox_archive">« {$lang->dvz_sb_archivelink}</a></p>
312</div>
313
314<div class="body">
315
316{$panel}
317
318<div class="window" style="height:{$mybb->settings[\'dvz_sb_height\']}px">
319<div class="data">
320{$html}
321</div>
322</div>
323
324</div>
325
326<script type="text/javascript" src="{$mybb->settings[\'bburl\']}/jscripts/dvz_shoutbox.js"></script>
327{$javascript}
328
329</div>',
330
331 'dvz_shoutbox_archive' => '<html>
332<head>
333<title>{$lang->dvz_sb_archive}</title>
334{$headerinclude}
335</head>
336<body>
337{$header}
338
339<script type="text/javascript" src="{$mybb->settings[\'bburl\']}/jscripts/dvz_shoutbox.js"></script>
340{$javascript}
341
342{$modoptions}
343
344{$multipage}
345
346<br />
347
348<div id="shoutbox">
349
350<div class="head">
351<strong>{$lang->dvz_sb_archive}</strong>
352{$last_read_link}
353</div>
354
355<div class="data">
356{$archive}
357</div>
358</div>
359
360<br />
361
362{$multipage}
363
364{$footer}
365</body>
366</html>',
367
368 'dvz_shoutbox_last_read_link' => '<p class="right"><a href="{$last_read_url}">{$lang->dvz_sb_last_read_link}</a> | <a href="{$unmark_all_url}">{$lang->dvz_sb_last_read_unmark_all}</a></p>',
369
370 'dvz_shoutbox_archive_modoptions' => '<table border="0" cellspacing="{$theme[\'borderwidth\']}" cellpadding="{$theme[\'tablespace\']}" class="tborder">
371<tr><td class="thead" colspan="2"><strong>{$lang->dvz_sb_mod}</strong></td></tr>
372<tr><td class="tcat">{$lang->dvz_sb_mod_banlist}</td><td class="tcat">{$lang->dvz_sb_mod_clear}</td></tr>
373<tr>
374<td class="trow1">
375<form action="" method="post">
376<input type="text" class="textbox" style="width:80%" name="banlist" value="{$blocked_users}" />
377<input type="hidden" name="postkey" value="{$mybb->post_code}" />
378<input type="submit" class="button" value="{$lang->dvz_sb_mod_banlist_button}" />
379</form>
380</td>
381<td class="trow1">
382<form action="" method="post">
383<select name="days">
384<option value="2">2 {$lang->days}</option>
385<option value="7">7 {$lang->days}</option>
386<option value="30">30 {$lang->days}</option>
387<option value="90">90 {$lang->days}</option>
388<option value="all">* {$lang->dvz_sb_mod_clear_all} *</option>
389</select>
390<input type="hidden" name="postkey" value="{$mybb->post_code}" />
391<input type="submit" class="button" value="{$lang->dvz_sb_mod_clear_button}" />
392</form>
393</td>
394</tr>
395</table>
396<br />',
397 ];
398
399 $data = [];
400
401 foreach ($templates as $name => $content) {
402 $data[] = [
403 'title' => $name,
404 'template' => $db->escape_string($content),
405 'sid' => -1,
406 'version' => 1,
407 'status' => '',
408 'dateline' => TIME_NOW,
409 ];
410 }
411
412 $db->insert_query_multiple('templates', $data);
413}
414
415function dvz_shoutbox_uninstall()
416{
417 global $db;
418
419 $settingGroupId = $db->fetch_field(
420 $db->simple_select('settinggroups', 'gid', "name='dvz_shoutbox'"),
421 'gid'
422 );
423
424 // delete settings
425 $db->delete_query('settinggroups', 'gid=' . (int)$settingGroupId);
426 $db->delete_query('settings', 'gid=' . (int)$settingGroupId);
427
428 rebuild_settings();
429
430 // delete templates
431 $db->delete_query('templates', "title IN('dvz_shoutbox', 'dvz_shoutbox_panel', 'dvz_shoutbox_archive', 'dvz_shoutbox_archive_modoptions')");
432
433 // delete data
434 if ($db->type == 'sqlite') {
435 $db->close_cursors();
436 }
437 $db->drop_table('dvz_shoutbox');
438 // Usuwanie zgloszen
439 $db->query("DROP TABLE ".TABLE_PREFIX."dvz_reports");
440}
441
442function dvz_shoutbox_is_installed()
443{
444 global $mybb;
445 return $mybb->settings['dvz_sb_num'] !== null;
446}
447
448
449class dvz_shoutbox
450{
451
452 // hooks
453 static function global_start()
454 {
455 global $mybb, $templatelist;
456
457 $mybb->binary_fields['dvz_shoutbox'] = ['ipaddress' => true];
458
459 if (defined('THIS_SCRIPT') && THIS_SCRIPT == 'index.php' && self::access_view()) {
460
461 if (!empty($templatelist)) {
462 $templatelist .= ',';
463 }
464
465 if ($mybb->get_input('action') == 'shoutbox_archive') {
466 // archive templates
467
468 $templatelist .= 'dvz_shoutbox_archive,dvz_shoutbox_last_read_link,multipage,multipage_page,multipage_page_current,multipage_prevpage,multipage_nextpage,multipage_start,multipage_end,multipage_jump_page';
469
470 if (self::access_mod()) {
471 $templatelist .= ',dvz_shoutbox_archive_modoptions';
472 }
473
474 } else {
475 // index templates
476 $templatelist .= 'dvz_shoutbox,dvz_shoutbox_panel';
477 }
478
479 }
480 }
481
482 static function global_end()
483 {
484 global $mybb;
485
486 if ($mybb->get_input('action') == 'shoutbox_archive' && self::access_view()) {
487 return self::show_archive();
488 }
489 }
490
491 static function xmlhttp()
492 {
493 global $mybb, $db, $charset, $plugins;
494
495 $mybb->binary_fields['dvz_shoutbox'] = ['ipaddress' => true];
496
497 switch ($mybb->get_input('action')) {
498
499 case 'dvz_sb_get_updates':
500
501 $permissions = (
502 self::access_view() &&
503 self::access_refresh()
504 );
505
506 $handler = function () use ($mybb, $db, $plugins) {
507
508 $syncConditions = $mybb->settings['dvz_sb_sync']
509 ? "OR (s.modified >= " . (time() - $mybb->settings['dvz_sb_interval']) . " AND s.id BETWEEN " . abs($mybb->get_input('first', MyBB::INPUT_INT)) . " AND " . abs($mybb->get_input('last', MyBB::INPUT_INT)) . ")"
510 : null
511 ;
512
513 $data = self::get_multiple("WHERE (s.id > " . abs($mybb->get_input('last', MyBB::INPUT_INT)) . " AND s.text IS NOT NULL) " . $syncConditions . " ORDER BY s.id DESC LIMIT " . self::async_limit());
514
515 $html = null; // JS-handled empty response
516 $sync = [];
517 $firstId = 0;
518 $lastId = 0;
519
520 while ($row = $db->fetch_array($data)) {
521
522 if ($row['id'] <= $mybb->get_input('last', MyBB::INPUT_INT)) {
523 // sync update
524
525 $sync[ $row['id'] ] = $row['text'] === null
526 ? null
527 : self::parse($row['text'], $row['username'])
528 ;
529
530 } else {
531 // new shout
532
533 $firstId = $row['id'];
534
535 if ($lastId == 0) {
536 $lastId = $row['id'];
537 }
538
539 $shout = self::render_shout($row);
540
541 $html = $mybb->settings['dvz_sb_reversed']
542 ? $shout . $html
543 : $html . $shout
544 ;
545
546 }
547
548 }
549
550 if ($html != null || !empty($sync)) {
551
552 $response = [];
553
554 if ($html != null) {
555
556 $response['html'] = $html;
557 $response['last'] = $lastId;
558
559 if ($mybb->get_input('first', MyBB::INPUT_INT) == 0) {
560 $response['first'] = $firstId;
561 }
562
563 }
564
565 if (!empty($sync)) {
566 $response['sync'] = $sync;
567 }
568
569 $plugins->run_hooks('dvz_shoutbox_get_updates', $response);
570
571 echo json_encode($response);
572
573 }
574 };
575
576 break;
577
578 case 'dvz_sb_recall':
579
580 $permissions = (
581 self::access_view() &&
582 self::access_refresh() &&
583 self::access_recall()
584 );
585
586 $handler = function () use ($mybb, $db, $plugins) {
587
588 $data = self::get_multiple("WHERE s.id < " . abs($mybb->get_input('first', MyBB::INPUT_INT)) . " AND s.text IS NOT NULL ORDER BY s.id DESC LIMIT " . abs((int)$mybb->settings['dvz_sb_num']));
589
590 $response = [];
591
592 $html = null; // JS-handled empty response
593 $firstId = 0;
594
595 while ($row = $db->fetch_array($data)) {
596
597 $firstId = $row['id'];
598
599 $shout = self::render_shout($row);
600
601 $html = $mybb->settings['dvz_sb_reversed']
602 ? $shout . $html
603 : $html . $shout
604 ;
605 }
606
607 if ($html != null) {
608 $response['html'] = $html;
609 }
610
611 if ($db->num_rows($data) < abs((int)$mybb->settings['dvz_sb_num'])) {
612 $response['end'] = 1;
613 }
614
615 if ($response) {
616 $response['first'] = $firstId;
617 }
618
619 $plugins->run_hooks('dvz_shoutbox_recall', $response);
620
621 echo json_encode($response);
622
623 };
624
625 break;
626
627 case 'dvz_sb_shout':
628
629 $permissions = (
630 self::access_shout() &&
631 verify_post_check($mybb->get_input('key'), true)
632 );
633
634 $handler = function () use ($mybb, $db, $plugins) {
635
636 if (!self::antiflood_pass() && !self::access_mod()) {
637 die('A'); // JS-handled error (Anti-flood)
638 }
639
640 $data = [
641 'uid' => (int)$mybb->user['uid'],
642 'text' => $mybb->get_input('text'),
643 'ipaddress' => $db->escape_binary( my_inet_pton(get_ip()) ),
644 ];
645
646 $plugins->run_hooks('dvz_shoutbox_shout', $data);
647
648 $data['shout_id'] = self::shout($data);
649
650 $plugins->run_hooks('dvz_shoutbox_shout_commit', $data);
651
652 };
653
654 break;
655
656 case 'dvz_sb_get':
657
658 $data = self::get($mybb->get_input('id', MyBB::INPUT_INT));
659
660 $permissions = (
661 (
662 self::access_mod() ||
663 (self::access_mod_own() && $data['uid'] == $mybb->user['uid'])
664 ) &&
665 verify_post_check($mybb->get_input('key'), true)
666 );
667
668 $handler = function () use ($data, $plugins) {
669
670 $plugins->run_hooks('dvz_shoutbox_get', $data);
671
672 echo json_encode([
673 'text' => $data['text'],
674 ]);
675
676 };
677
678 break;
679
680 case 'dvz_sb_update':
681
682 $data = self::get($mybb->get_input('id', MyBB::INPUT_INT));
683
684 $permissions = (
685 $data &&
686 self::can_mod($data) &&
687 verify_post_check($mybb->get_input('key'), true)
688 );
689
690 $handler = function () use ($mybb, $data, $plugins) {
691
692 $plugins->run_hooks('dvz_shoutbox_update', $data);
693
694 self::update($mybb->get_input('id', MyBB::INPUT_INT), $mybb->get_input('text'));
695
696 $data['text'] = $mybb->get_input('text');
697
698 $plugins->run_hooks('dvz_shoutbox_update_commit', $data);
699
700 echo self::parse($mybb->get_input('text'), self::get_username($mybb->get_input('id', MyBB::INPUT_INT)));
701
702 };
703
704 break;
705
706 case 'dvz_sb_delete':
707
708 $permissions = (
709 self::can_mod($mybb->get_input('id', MyBB::INPUT_INT)) &&
710 verify_post_check($mybb->get_input('key'), true)
711 );
712
713 $handler = function () use ($mybb, $plugins) {
714
715 $plugins->run_hooks('dvz_shoutbox_delete');
716
717 $result = self::delete($mybb->get_input('id', MyBB::INPUT_INT));
718
719 $plugins->run_hooks('dvz_shoutbox_delete_commit', $result);
720
721 };
722
723 break;
724
725 // Zgloszenia
726 case 'dvz_sb_report':
727 echo dvz_shoutbox::reportShout($mybb->input);
728 break;
729
730 }
731
732 if (isset($permissions)) {
733
734 if ($permissions == false) {
735 echo 'P'; // JS-handled error (Permissions)
736 } else {
737
738 header('Content-type: text/plain; charset=' . $charset);
739 header('Cache-Control: no-store'); // force update on load
740 $handler();
741
742 }
743
744 }
745 }
746
747 static function load_window()
748 {
749 global $templates, $dvz_shoutbox, $lang, $mybb, $db, $theme;
750
751 $lang->load('dvz_shoutbox');
752
753 // MyBB template
754 $dvz_shoutbox = null;
755
756 // dvz_shoutbox template
757 $javascript = null;
758 $panel = null;
759 $classes = null;
760
761 if (self::access_view()) {
762
763 if (self::is_user()) {
764
765 // message: blocked
766 if (self::is_blocked()) {
767 $panel = '<div class="panel blocked"><p>' . $lang->dvz_sb_user_blocked . '</p></div>';
768 }
769 // message: minimum posts
770 else if (!self::access_minposts() && !self::access_mod()) {
771 $panel = '<div class="panel minposts"><p>' . str_replace('{MINPOSTS}', (int)$mybb->settings['dvz_sb_minposts'], $lang->dvz_sb_minposts) . '</p></div>';
772 }
773 // shout form
774 else if (self::access_shout()) {
775 $maxlength = $mybb->settings['dvz_sb_maxlength'] ? (int)$mybb->settings['dvz_sb_maxlength'] : null;
776 eval('$panel = "' . $templates->get('dvz_shoutbox_panel') . '";');
777 }
778
779 }
780
781 $js = null;
782
783 // configuration
784 $js .= 'dvz_shoutbox.interval = ' . (self::access_refresh() ? (float)$mybb->settings['dvz_sb_interval'] : 0) . ';' . PHP_EOL;
785 $js .= 'dvz_shoutbox.antiflood = ' . (self::access_mod() ? 0 : (float)$mybb->settings['dvz_sb_antiflood']) . ';' . PHP_EOL;
786 $js .= 'dvz_shoutbox.maxShouts = ' . (int)$mybb->settings['dvz_sb_num'] . ';' . PHP_EOL;
787 $js .= 'dvz_shoutbox.awayTime = ' . (float)$mybb->settings['dvz_sb_away'] . '*1000;' . PHP_EOL;
788 $js .= 'dvz_shoutbox.lang = [\'' . $lang->dvz_sb_delete_confirm . '\', \'' . str_replace('{ANTIFLOOD}', (float)$mybb->settings['dvz_sb_antiflood'], $lang->dvz_sb_antiflood) . '\', \''.$lang->dvz_sb_permissions.'\'];' . PHP_EOL;
789
790 // mark unread
791 if ($mybb->settings['dvz_sb_mark_unread']) {
792 $js .= 'dvz_shoutbox.markUnread = true;' . PHP_EOL;
793 }
794
795 // reversed order
796 if ($mybb->settings['dvz_sb_reversed']) {
797 $js .= 'dvz_shoutbox.reversed = true;' . PHP_EOL;
798 }
799
800 // lazyload
801 if (in_array($mybb->settings['dvz_sb_lazyload'], ['off', 'start', 'always'])) {
802 $js .= 'dvz_shoutbox.lazyMode = \'' . $mybb->settings['dvz_sb_lazyload'] . '\';' . PHP_EOL;
803 $js .= '$(window).bind(\'scroll resize\', dvz_shoutbox.checkVisibility);' . PHP_EOL;
804 }
805
806 // away mode
807 if ($mybb->settings['dvz_sb_away']) {
808 $js .= '$(window).on(\'mousemove click dblclick keydown scroll\', dvz_shoutbox.updateActivity);' . PHP_EOL;
809 }
810
811 // shoutbox status
812 $status =
813 (!isset($mybb->cookies['dvz_sb_status']) && $mybb->settings['dvz_sb_status'] == 1) ||
814 $mybb->cookies['dvz_sb_status'] == '1'
815 ;
816
817 $js .= 'dvz_shoutbox.status = ' . (int)$status . ';' . PHP_EOL;
818
819 if ($status == false) {
820 $classes .= ' collapsed';
821 }
822
823 $html = null;
824 $firstId = 0;
825 $lastId = 0;
826
827 if ($status == true) {
828
829 // preloaded shouts
830 $data = self::get_multiple("WHERE s.text IS NOT NULL ORDER BY s.id DESC LIMIT " . abs((int)$mybb->settings['dvz_sb_num']));
831
832 while ($row = $db->fetch_array($data)) {
833
834 $firstId = $row['id'];
835
836 if ($lastId == 0) {
837 $lastId = $row['id'];
838 }
839
840 $shout = self::render_shout($row);
841
842 $html = $mybb->settings['dvz_sb_reversed']
843 ? $shout . $html
844 : $html . $shout
845 ;
846 }
847
848 }
849
850 if (self::access_recall()) {
851 $js .= 'dvz_shoutbox.recalling = true;' . PHP_EOL;
852 }
853
854 if (self::access_refresh()) {
855 $js .= 'setTimeout(\'dvz_shoutbox.loop()\', ' . (float)$mybb->settings['dvz_sb_interval'] . ' * 1000);' . PHP_EOL;
856 }
857
858 $javascript = '
859<script>
860' . $js . '
861dvz_shoutbox.firstId = ' . $firstId . ';
862dvz_shoutbox.lastId = ' . $lastId . ';
863dvz_shoutbox.parseEntries();
864dvz_shoutbox.updateActivity();
865</script>';
866
867 eval('$dvz_shoutbox = "' . $templates->get('dvz_shoutbox') . '";');
868
869 }
870 }
871
872 static function show_archive()
873 {
874 global $db, $mybb, $templates, $lang, $theme, $footer, $headerinclude, $header, $charset;
875
876 $lang->load('dvz_shoutbox');
877
878 header('Content-type: text/html; charset=' . $charset);
879
880 add_breadcrumb($lang->dvz_sb_shoutbox, "index.php?action=shoutbox_archive");
881
882 // moderation panel
883 if (self::access_mod()) {
884
885 if (isset($mybb->input['banlist']) && verify_post_check($mybb->get_input('postkey'))) {
886 self::banlist_update($mybb->get_input('banlist'));
887 }
888
889 if ($mybb->get_input('days') && verify_post_check($mybb->get_input('postkey'))) {
890 if ($mybb->get_input('days') == 'all') {
891 self::clear();
892 } else {
893 $allowed = [2, 7, 30, 90];
894 if (in_array($mybb->get_input('days'), $allowed)) {
895 self::clear($mybb->get_input('days'));
896 }
897 }
898 }
899
900 $blocked_users = htmlspecialchars_uni($mybb->settings['dvz_sb_blocked_users']);
901 eval('$modoptions = "' . $templates->get("dvz_shoutbox_archive_modoptions") . '";');
902
903 } else {
904 $modoptions = null;
905 }
906
907 // unmark all unread messages
908 if ($mybb->get_input('unmark_all') && verify_post_check($mybb->get_input('postkey'))) {
909 my_unsetcookie('dvz_sb_last_read');
910 }
911
912 // pagination
913 $perPage = abs((int)$mybb->settings['dvz_sb_num_archive']);
914 $items = self::count();
915
916 $requestedId = $mybb->get_input('sid', MyBB::INPUT_INT);
917
918 if ($requestedId && self::get($requestedId)) {
919
920 if ($perPage == 0) {
921 $page = 0;
922 } else {
923 $itemsAfter = self::count('id > ' . $requestedId);
924 $itemPage = ceil( ($itemsAfter + 1) / $perPage );
925
926 $page = $itemPage;
927 }
928
929 } else {
930
931 $page = abs($mybb->get_input('page', MyBB::INPUT_INT));
932
933 if ($perPage == 0) {
934 $pages = 0;
935 } else {
936 $pages = ceil($items / $perPage);
937 }
938
939 if (!$page || $page < 1 || $page > $pages) {
940 $page = 1;
941 }
942
943 }
944
945 $limitStart = ($page - 1) * $perPage;
946
947 if ($items > $perPage && $perPage > 0) {
948 $multipage = multipage($items, $perPage, $page, 'index.php?action=shoutbox_archive');
949 }
950
951 $limit = $perPage;
952
953 if ($mybb->settings['dvz_sb_mark_unread'] && isset($mybb->cookies['dvz_sb_last_read'])) {
954 $limit += 1;
955 }
956
957 $data = self::get_multiple("WHERE s.text IS NOT NULL ORDER by s.id DESC LIMIT $limitStart,$limit");
958
959 $firstId = null;
960 $lastId = null;
961
962 $archive = null;
963
964 $rowCount = 1;
965
966 while ($row = $db->fetch_array($data)) {
967
968 if ($rowCount > $perPage) {
969
970 $nextPageLastId = $row['id'];
971
972 } else {
973
974 if ($mybb->settings['dvz_sb_mark_unread'] && isset($mybb->cookies['dvz_sb_last_read']) && $row['id'] > $mybb->cookies['dvz_sb_last_read']) {
975 $row['unread'] = true;
976 }
977
978 $archive .= self::render_shout($row, true);
979
980 if ($lastId == null) {
981 $lastId = $row['id'];
982 }
983
984 $firstId = $row['id'];
985
986 $rowCount++;
987
988 }
989
990 }
991
992 // update last read information
993 if ($mybb->settings['dvz_sb_mark_unread']) {
994 if (
995 !isset($mybb->cookies['dvz_sb_last_read']) ||
996 (
997 $lastId > $mybb->cookies['dvz_sb_last_read'] &&
998 (!isset($nextPageLastId) || $mybb->cookies['dvz_sb_last_read'] >= $nextPageLastId)
999 )
1000 ) {
1001 my_setcookie('dvz_sb_last_read', $lastId);
1002 }
1003 }
1004
1005 // last read link
1006 if (
1007 $mybb->settings['dvz_sb_mark_unread'] &&
1008 isset($mybb->cookies['dvz_sb_last_read']) &&
1009 !($page == 1 && $lastId == abs((int)$mybb->cookies['dvz_sb_last_read']))
1010 ) {
1011
1012 $sid = abs((int)$mybb->cookies['dvz_sb_last_read']);
1013 $last_read_url = $mybb->settings['bburl'] . '/index.php?action=shoutbox_archive&sid=' . $sid . '#sid' . $sid;
1014 $unmark_all_url = $mybb->settings['bburl'] . '/index.php?action=shoutbox_archive&unmark_all=1&postkey=' . $mybb->post_code;
1015
1016 eval('$last_read_link = "' . $templates->get('dvz_shoutbox_last_read_link') . '";');
1017
1018 } else {
1019 $last_read_link = null;
1020 }
1021
1022 $javascript = '
1023<script>
1024dvz_shoutbox.lang = [\'' . $lang->dvz_sb_delete_confirm . '\', \'' . str_replace('{ANTIFLOOD}', (float)$mybb->settings['dvz_sb_antiflood'], $lang->dvz_sb_antiflood) . '\', \'' . $lang->dvz_sb_permissions . '\'];
1025</script>';
1026
1027 eval('$content = "' . $templates->get("dvz_shoutbox_archive") . '";');
1028
1029 output_page($content);
1030
1031 exit;
1032 }
1033
1034 static function user_merge()
1035 {
1036 global $db, $source_user, $destination_user;
1037 return $db->update_query('dvz_shoutbox', ['uid' => (int)$destination_user['uid']], 'uid=' . (int)$source_user['uid']);
1038 }
1039
1040 static function activity(&$user_activity)
1041 {
1042 $location = parse_url($user_activity['location']);
1043 $filename = basename($location['path']);
1044
1045 parse_str(html_entity_decode($location['query']), $parameters);
1046
1047 if ($filename == 'index.php' && $parameters['action'] == 'shoutbox_archive') {
1048 $user_activity['activity'] = 'dvz_shoutbox_archive';
1049 }
1050 }
1051
1052 static function activity_translate(&$data)
1053 {
1054 global $lang;
1055
1056 $lang->load('dvz_shoutbox');
1057
1058 if ($data['user_activity']['activity'] == 'dvz_shoutbox_archive') {
1059 $data['location_name'] = sprintf($lang->dvz_sb_activity, 'index.php?action=shoutbox_archive');
1060 }
1061 }
1062
1063 static function clearcookies()
1064 {
1065 global $remove_cookies;
1066 $remove_cookies[] = 'dvz_sb_status';
1067 $remove_cookies[] = 'dvz_sb_last_read';
1068 }
1069
1070 static function admin_config_settings_change()
1071 {
1072 global $lang;
1073 $lang->load('dvz_shoutbox');
1074 }
1075
1076 // data handling
1077 static function get($id)
1078 {
1079 global $db;
1080
1081 return $db->fetch_array(
1082 $db->simple_select('dvz_shoutbox s', '*', 'id=' . (int)$id . ' AND s.text IS NOT NULL')
1083 );
1084 }
1085
1086 static function get_multiple($clauses)
1087 {
1088 global $db;
1089 return $db->query("
1090 SELECT
1091 s.*, u.username, u.usergroup, u.displaygroup, u.avatar
1092 FROM
1093 " . TABLE_PREFIX . "dvz_shoutbox s
1094 LEFT JOIN " . TABLE_PREFIX . "users u ON u.uid = s.uid
1095 " . $clauses . "
1096 ");
1097 }
1098
1099 static function get_username($id)
1100 {
1101 global $db;
1102 return $db->fetch_field(
1103 $db->query("SELECT username FROM " . TABLE_PREFIX . "users u, " . TABLE_PREFIX . "dvz_shoutbox s WHERE u.uid=s.uid AND s.id=" . (int)$id),
1104 'username'
1105 );
1106 }
1107
1108 static function user_last_shout_time($uid)
1109 {
1110 global $db;
1111 return $db->fetch_field(
1112 $db->simple_select('dvz_shoutbox s', 'date', 'uid=' . (int)$uid . ' AND s.text IS NOT NULL', [
1113 'order_by' => 'date',
1114 'order_dir' => 'desc',
1115 'limit' => 1,
1116 ]),
1117 'date'
1118 );
1119 }
1120
1121 static function count($where = false)
1122 {
1123 global $db;
1124 return $db->fetch_field(
1125 $db->simple_select('dvz_shoutbox', 'COUNT(text) as n', $where),
1126 'n'
1127 );
1128 }
1129
1130 static function shout($data)
1131 {
1132 global $mybb, $db;
1133
1134 if ($mybb->settings['dvz_sb_maxlength'] > 0) {
1135 $data['text'] = mb_substr($data['text'], 0, $mybb->settings['dvz_sb_maxlength']);
1136 }
1137
1138 foreach ($data as $key => &$value) {
1139 if (!in_array($key, array_keys($mybb->binary_fields['dvz_shoutbox']))) {
1140 $value = $db->escape_string($value);
1141 }
1142 }
1143
1144 $data['date'] = TIME_NOW;
1145
1146 return $db->insert_query('dvz_shoutbox', $data);
1147 }
1148
1149 static function update($id, $text)
1150 {
1151 global $db;
1152 return $db->update_query('dvz_shoutbox', [
1153 'text' => $db->escape_string($text),
1154 'modified' => time(),
1155 ], 'id=' . (int)$id);
1156 }
1157
1158 static function banlist_update($new)
1159 {
1160 global $db;
1161
1162 $db->update_query('settings', ['value' => $db->escape_string($new)], "name='dvz_sb_blocked_users'");
1163
1164 rebuild_settings();
1165 }
1166
1167 static function delete($id)
1168 {
1169 global $mybb, $db;
1170
1171 if ($mybb->settings['dvz_sb_sync']) {
1172 return $db->update_query('dvz_shoutbox', [
1173 'text' => 'NULL',
1174 'modified' => time(),
1175 ], 'id=' . (int)$id, false, true);
1176 } else {
1177 return $db->delete_query('dvz_shoutbox', 'id=' . (int)$id);
1178 }
1179 }
1180
1181 static function clear($days = false)
1182 {
1183 global $db;
1184
1185 if ($days) {
1186 $where = 'date < ' . ( TIME_NOW - ((int)$days * 86400) );
1187 } else {
1188 $where = false;
1189 }
1190
1191 return $db->delete_query('dvz_shoutbox', $where);
1192 }
1193
1194 // permissions + zgloszenia
1195 static function is_user () {
1196 global $mybb;
1197 return !($mybb->user['usergroup'] == 1 && $mybb->user['uid'] < 1);
1198 }
1199
1200 static function is_blocked () {
1201 global $db, $mybb, $lang;
1202
1203 $uid = $mybb->user['uid'];
1204 $query = $db->simple_select("dvz_reports_banned", 'id, reason, unbantime', "uid='" . $uid . "'");
1205 if($query->num_rows === 1) {
1206 $data = $query->fetch_row();
1207 if($data[2] < strtotime('+1 hour', time())) {
1208 $uid = $db->escape_string($data[0]);
1209 $db->delete_query("dvz_reports_banned", "id ='" . $uid . "'");
1210 return false;
1211 }
1212
1213 $lang->load('custom');
1214
1215 return '<br />' . $lang->sprintf($lang->shoutbox_reason, $data[1]) . '<br />' . $lang->sprintf($lang->unbanat, date('d-M-Y H:i:s', $data[2]));
1216 }
1217 return false;
1218 }
1219 static function access_view()
1220 {
1221 $array = self::settings_get_csv('groups_view');
1222 return $array[0] == -1 || is_member($array);
1223 }
1224
1225 static function access_refresh()
1226 {
1227 $array = self::settings_get_csv('groups_refresh');
1228 return $array[0] == -1 || is_member($array);
1229 }
1230
1231 static function access_shout()
1232 {
1233 $array = self::settings_get_csv('groups_shout');
1234
1235 return (
1236 self::is_user() &&
1237 !self::is_blocked() &&
1238 (
1239 self::access_mod() ||
1240 (
1241 self::access_view() &&
1242 self::access_minposts() &&
1243 $array[0] == -1 || is_member($array)
1244 )
1245 )
1246 );
1247 }
1248
1249 static function access_recall()
1250 {
1251 $array = self::settings_get_csv('groups_recall');
1252 return $array[0] == -1 || is_member($array);
1253 }
1254
1255 static function access_mod()
1256 {
1257 global $mybb;
1258
1259 $array = self::settings_get_csv('groups_mod');
1260
1261 return (
1262 ($array[0] == -1 || is_member($array)) ||
1263 ($mybb->settings['dvz_sb_supermods'] && $mybb->usergroup['issupermod'])
1264 );
1265 }
1266
1267 static function access_mod_own()
1268 {
1269 $array = self::settings_get_csv('groups_mod_own');
1270
1271 return $array[0] == -1 || is_member($array);
1272 }
1273
1274 static function access_minposts()
1275 {
1276 global $mybb;
1277 return $mybb->user['postnum'] >= $mybb->settings['dvz_sb_minposts'];
1278 }
1279
1280 static function can_mod($data)
1281 {
1282 global $mybb;
1283
1284 if (self::access_mod()) {
1285 return true;
1286 } else if (self::access_mod_own() && self::access_shout()) {
1287
1288 if (is_int($data)) {
1289 $data = self::get($shoutId);
1290 }
1291
1292 if ($data['uid'] == $mybb->user['uid']) {
1293 return true;
1294 }
1295
1296 }
1297
1298 return false;
1299 }
1300
1301 // core
1302 static function render_shout($data, $static = false)
1303 {
1304 global $mybb;
1305
1306 $id = (int)$data['id'];
1307 $text = self::parse($data['text'], $data['username']);
1308 $date = htmlspecialchars_uni(my_date($mybb->settings['dvz_sb_dateformat'], $data['date']));
1309 $username = htmlspecialchars_uni($data['username']);
1310 $user = build_profile_link(format_name($username, $data['usergroup'], $data['displaygroup']), (int)$data['uid']);
1311 $avatar = '<img src="' . (empty($data['avatar']) ? htmlspecialchars_uni($mybb->settings['useravatar']) : htmlspecialchars_uni($data['avatar'])) . '" alt="avatar" />';
1312
1313 $staticLink = $mybb->settings['bburl'] . '/index.php?action=shoutbox_archive&sid=' . $id . '#sid' . $id;
1314
1315 $classes = 'entry';
1316 $notes = null;
1317 $attributes = null;
1318
1319 $own = $data['uid'] == $mybb->user['uid'];
1320
1321 if (!empty($data['unread'])) {
1322 $classes .= ' unread';
1323 }
1324
1325 if ($static) {
1326
1327 if (self::access_mod()) {
1328 $notes .= '<span class="ip">' . my_inet_ntop($data['ipaddress']) . '</span>';
1329 }
1330
1331 if (
1332 self::access_mod() ||
1333 (self::access_mod_own() && $own)
1334 ) {
1335 $notes .= '<a href="" class="mod edit">E</a><a href="" class="mod del">X</a>';
1336 }
1337
1338 $attributes .= ' id="sid' . $id . '"';
1339
1340 }
1341
1342 if (
1343 self::access_mod() ||
1344 (self::access_mod_own() && $own)
1345 ) {
1346 $attributes .= ' data-mod';
1347 }
1348
1349 if ($own) {
1350 $attributes .= ' data-own';
1351
1352 //zgloszenia
1353 $notes .= '<a href="" class="mod report">REPORT</a>';
1354
1355 }
1356
1357 return '
1358<div class="' . $classes . '" data-id="' . $id . '" data-username="' . $username . '"' . $attributes . '>
1359 <div class="avatar">' . $avatar . '</div>
1360 <div class="user">' . $user . '</div>
1361 <div class="text">' . $text . '</div>
1362 <div class="info">' . $notes . '<a href="' . $staticLink . '"><span class="date">' . $date . '</span></a></div>
1363</div>';
1364 }
1365
1366 static function parse($message, $me_username)
1367 {
1368 global $mybb;
1369
1370 require_once MYBB_ROOT . 'inc/class_parser.php';
1371
1372 $parser = new postParser;
1373 $options = [
1374 'allow_mycode' => $mybb->settings['dvz_sb_mycode'],
1375 'allow_smilies' => $mybb->settings['dvz_sb_smilies'],
1376 'allow_imgcode' => 0,
1377 'filter_badwords' => 1,
1378 'me_username' => $me_username,
1379 ];
1380
1381 return $parser->parse_message($message, $options);
1382 }
1383
1384 static function antiflood_pass()
1385 {
1386 global $mybb;
1387 return (
1388 !$mybb->settings['dvz_sb_antiflood'] ||
1389 ( TIME_NOW - self::user_last_shout_time($mybb->user['uid']) ) > $mybb->settings['dvz_sb_antiflood']
1390 );
1391 }
1392
1393 static function settings_get_csv($name)
1394 {
1395 global $mybb;
1396 return array_filter( explode(',', $mybb->settings['dvz_sb_' . $name]) );
1397 }
1398
1399 static function async_limit()
1400 {
1401 global $mybb;
1402 return max(
1403 abs((int)$mybb->settings['dvz_sb_num']),
1404 abs((int)$mybb->settings['dvz_sb_num_archive'])
1405 );
1406 }
1407
1408//zgloszenia
1409 static function reportShout($postdata)
1410 {
1411 global $mybb, $db;
1412 if (verify_post_check($postdata['key'])) {
1413 if (self::access_shout()) {
1414 $id = $db->escape_string($postdata['id']);
1415 $getPost = $db->write_query("SELECT id FROM " .TABLE_PREFIX. "dvz_shoutbox WHERE id = '$id'");
1416 if ($getPost->num_rows === 1) {
1417 //Store report
1418 $data = array(
1419 'shid' => $db->escape_string($postdata['id']),
1420 'uid' => $db->escape_string($mybb->user['uid']),
1421 'reason' => $db->escape_string($postdata['reason']),
1422 'date' => time(),
1423 'ip' => $db->escape_string(get_ip()),
1424 );
1425
1426 $insert = $db->insert_query('dvz_reports', $data);
1427 if ($insert) {
1428 return true;
1429 }
1430 return false;
1431 }
1432 return false;
1433 }
1434
1435 return false;
1436 }
1437 }
1438
1439}
1440
1441?>