· 6 years ago · Sep 03, 2019, 10:50 AM
1NEW CHAT CODES :PHP
2
3
4<?php
5/*
6* LE CHAT-PHP - a PHP Chat based on LE CHAT - Main program
7*
8* Copyright (C) 2015-2018 Daniel Winzen <d@winzen4.de>
9*
10* This program is free software: you can redistribute it and/or modify
11* it under the terms of the GNU General Public License as published by
12* the Free Software Foundation, either version 3 of the License, or
13* (at your option) any later version.
14*
15* This program is distributed in the hope that it will be useful,
16* but WITHOUT ANY WARRANTY; without even the implied warranty of
17* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18* GNU General Public License for more details.
19*
20* You should have received a copy of the GNU General Public License
21* along with this program. If not, see <http://www.gnu.org/licenses/>.
22*/
23
24/*
25* status codes
26* 0 - Kicked/Banned
27* 1 - Guest
28* 2 - Applicant
29* 3 - Member
30* 4 - System message
31* 5 - Moderator
32* 6 - Super-Moderator
33* 7 - Admin
34* 8 - Super-Admin
35* 9 - Private messages
36*/
37
38send_headers();
39// initialize and load variables/configuration
40$I=[];// Translations
41$L=[];// Languages
42$U=[];// This user data
43$db;// Database connection
44$memcached;// Memcached connection
45$language;// user selected language
46load_config();
47// set session variable to cookie if cookies are enabled
48if(!isset($_REQUEST['session']) && isset($_COOKIE[COOKIENAME])){
49 $_REQUEST['session']=$_COOKIE[COOKIENAME];
50}
51load_lang();
52check_db();
53cron();
54route();
55
56// main program: decide what to do based on queries
57function route(){
58 global $U;
59 if(!isset($_REQUEST['action'])){
60 send_login();
61 }elseif($_REQUEST['action']==='view'){
62 check_session();
63 send_messages();
64 }elseif($_REQUEST['action']==='redirect' && !empty($_REQUEST['url'])){
65 send_redirect($_REQUEST['url']);
66 }elseif($_REQUEST['action']==='wait'){
67 parse_sessions();
68 send_waiting_room();
69 }elseif($_REQUEST['action']==='post'){
70 check_session();
71 if(isset($_REQUEST['kick']) && isset($_REQUEST['sendto']) && $_REQUEST['sendto']!=='s &'){
72 if($U['status']>=5 || ($U['status']>=3 && get_count_mods()==0 && get_setting('memkick'))){
73 if(isset($_REQUEST['what']) && $_REQUEST['what']==='purge'){
74 kick_chatter([$_REQUEST['sendto']], $_REQUEST['message'], true);
75 }else{
76 kick_chatter([$_REQUEST['sendto']], $_REQUEST['message'], false);
77 }
78 }
79 }elseif(isset($_REQUEST['message']) && isset($_REQUEST['sendto'])){
80 send_post(validate_input());
81 }
82 send_post();
83 }elseif($_REQUEST['action']==='login'){
84 check_login();
85 send_frameset();
86 }elseif($_REQUEST['action']==='controls'){
87 check_session();
88 send_controls();
89 }elseif($_REQUEST['action']==='greeting'){
90 check_session();
91 send_greeting();
92 }elseif($_REQUEST['action']==='delete'){
93 check_session();
94 if($_REQUEST['what']==='all'){
95 if(isset($_REQUEST['confirm'])){
96 del_all_messages($U['nickname'], $U['status']==1 ? $U['entry'] : 0);
97 }else{
98 send_del_confirm();
99 }
100 }elseif($_REQUEST['what']==='last'){
101 del_last_message();
102 }
103 send_post();
104 }elseif($_REQUEST['action']==='profile'){
105 check_session();
106 $arg='';
107 if(!isset($_REQUEST['do'])){
108 }elseif($_REQUEST['do']==='save'){
109 $arg=save_profile();
110 }elseif($_REQUEST['do']==='delete'){
111 if(isset($_REQUEST['confirm'])){
112 delete_account();
113 }else{
114 send_delete_account();
115 }
116 }
117 send_profile($arg);
118 }elseif($_REQUEST['action']==='logout'){
119 kill_session();
120 send_logout();
121 }elseif($_REQUEST['action']==='colours'){
122 check_session();
123 send_colours();
124 }elseif($_REQUEST['action']==='notes'){
125 check_session();
126 if(isset($_REQUEST['do']) && $_REQUEST['do']==='admin' && $U['status']>6){
127 send_notes(0);
128 }elseif(isset($_REQUEST['do']) && $_REQUEST['do']==='staff' && $U['status']>=5){
129 send_notes(1);
130 }
131 if($U['status']<3 || !get_setting('personalnotes')){
132 send_access_denied();
133 }
134 send_notes(2);
135 }elseif($_REQUEST['action']==='help'){
136 check_session();
137 send_help();
138 }elseif($_REQUEST['action']==='inbox'){
139 check_session();
140 if(isset($_REQUEST['do'])){
141 clean_inbox_selected();
142 }
143 send_inbox();
144 }elseif($_REQUEST['action']==='download'){
145 send_download();
146 }elseif($_REQUEST['action']==='admin'){
147 check_session();
148 send_admin(route_admin());
149 }elseif($_REQUEST['action']==='setup'){
150 route_setup();
151 }else{
152 send_login();
153 }
154}
155
156function route_admin(){
157 global $U, $db;
158 if($U['status']<5){
159 send_access_denied();
160 }
161 if(!isset($_REQUEST['do'])){
162 }elseif($_REQUEST['do']==='clean'){
163 if($_REQUEST['what']==='choose'){
164 send_choose_messages();
165 }elseif($_REQUEST['what']==='selected'){
166 clean_selected($U['status'], $U['nickname']);
167 }elseif($_REQUEST['what']==='room'){
168 clean_room();
169 }elseif($_REQUEST['what']==='nick'){
170 $stmt=$db->prepare('SELECT null FROM ' . PREFIX . 'members WHERE nickname=? AND status>=?;');
171 $stmt->execute([$_REQUEST['nickname'], $U['status']]);
172 if(!$stmt->fetch(PDO::FETCH_ASSOC)){
173 del_all_messages($_REQUEST['nickname'], 0);
174 }
175 }
176 }elseif($_REQUEST['do']==='kick'){
177 if(isset($_REQUEST['name'])){
178 if(isset($_REQUEST['what']) && $_REQUEST['what']==='purge'){
179 kick_chatter($_REQUEST['name'], $_REQUEST['kickmessage'], true);
180 }else{
181 kick_chatter($_REQUEST['name'], $_REQUEST['kickmessage'], false);
182 }
183 }
184 }elseif($_REQUEST['do']==='logout'){
185 if(isset($_REQUEST['name'])){
186 logout_chatter($_REQUEST['name']);
187 }
188 }elseif($_REQUEST['do']==='sessions'){
189 if(isset($_REQUEST['kick']) && isset($_REQUEST['nick'])){
190 kick_chatter([$_REQUEST['nick']], '', false);
191 }elseif(isset($_REQUEST['logout']) && isset($_REQUEST['nick'])){
192 logout_chatter([$_REQUEST['nick']], '', false);
193 }
194 send_sessions();
195 }elseif($_REQUEST['do']==='register'){
196 return register_guest(3, $_REQUEST['name']);
197 }elseif($_REQUEST['do']==='superguest'){
198 return register_guest(2, $_REQUEST['name']);
199 }elseif($_REQUEST['do']==='status'){
200 return change_status($_REQUEST['name'], $_REQUEST['set']);
201 }elseif($_REQUEST['do']==='regnew'){
202 return register_new($_REQUEST['name'], $_REQUEST['pass']);
203 }elseif($_REQUEST['do']==='approve'){
204 approve_session();
205 send_approve_waiting();
206 }elseif($_REQUEST['do']==='guestaccess'){
207 if(isset($_REQUEST['guestaccess']) && preg_match('/^[0123]$/', $_REQUEST['guestaccess'])){
208 update_setting('guestaccess', $_REQUEST['guestaccess']);
209 }
210 }elseif($_REQUEST['do']==='filter'){
211 send_filter(manage_filter());
212 }elseif($_REQUEST['do']==='linkfilter'){
213 send_linkfilter(manage_linkfilter());
214 }elseif($_REQUEST['do']==='topic'){
215 if(isset($_REQUEST['topic'])){
216 update_setting('topic', htmlspecialchars($_REQUEST['topic']));
217 }
218 }elseif($_REQUEST['do']==='passreset'){
219 return passreset($_REQUEST['name'], $_REQUEST['pass']);
220 }
221}
222
223function route_setup(){
224 global $U;
225 if(!valid_admin()){
226 send_alogin();
227 }
228 $C['bool_settings']=['suguests', 'imgembed', 'timestamps', 'trackip', 'memkick', 'forceredirect', 'incognito', 'sendmail', 'modfallback', 'disablepm', 'eninbox', 'enablegreeting', 'sortupdown', 'hidechatters', 'enfileupload', 'personalnotes', 'filtermodkick'];
229 $C['colour_settings']=['colbg', 'coltxt'];
230 $C['msg_settings']=['msgenter', 'msgexit', 'msgmemreg', 'msgsureg', 'msgkick', 'msgmultikick', 'msgallkick', 'msgclean', 'msgsendall', 'msgsendmem', 'msgsendmod', 'msgsendadm', 'msgsendprv', 'msgattache'];
231 $C['number_settings']=['memberexpire', 'guestexpire', 'kickpenalty', 'entrywait', 'captchatime', 'messageexpire', 'messagelimit', 'maxmessage', 'maxname', 'minpass', 'defaultrefresh', 'numnotes', 'maxuploadsize'];
232 $C['textarea_settings']=['rulestxt', 'css', 'disabletext'];
233 $C['text_settings']=['dateformat', 'captchachars', 'redirect', 'chatname', 'mailsender', 'mailreceiver', 'nickregex', 'passregex', 'externalcss'];
234 $C['settings']=array_merge(['guestaccess', 'englobalpass', 'globalpass', 'captcha', 'dismemcaptcha', 'topic', 'guestreg', 'defaulttz'], $C['bool_settings'], $C['colour_settings'], $C['msg_settings'], $C['number_settings'], $C['textarea_settings'], $C['text_settings']); // All settings in the database
235 if(!isset($_REQUEST['do'])){
236 }elseif($_REQUEST['do']==='save'){
237 save_setup($C);
238 }elseif($_REQUEST['do']==='backup' && $U['status']==8){
239 send_backup($C);
240 }elseif($_REQUEST['do']==='restore' && $U['status']==8){
241 restore_backup($C);
242 send_backup($C);
243 }elseif($_REQUEST['do']==='destroy' && $U['status']==8){
244 if(isset($_REQUEST['confirm'])){
245 destroy_chat($C);
246 }else{
247 send_destroy_chat();
248 }
249 }
250 send_setup($C);
251}
252
253// html output subs
254function print_stylesheet($init=false){
255 global $U;
256 //default css
257 echo '<style type="text/css">';
258 echo 'body{background-color:#000000;color:#FFFFFF;font-size:14px;text-align:center;} ';
259 echo 'a:visited{color:#B33CB4;} a:active{color:#FF0033;} a:link{color:#0000FF;} #messages{word-wrap:break-word;} ';
260 echo 'input,select,textarea{color:#FFFFFF;background-color:#000000;} .messages a img{width:15%} .messages a:hover img{width:35%} ';
261 echo '.error{color:#FF0033;text-align:left;} .delbutton{background-color:#660000;} .backbutton{background-color:#004400;} #exitbutton{background-color:#AA0000;} ';
262 echo '.setup table table,.admin table table,.profile table table{width:100%;text-align:left} ';
263 echo '.alogin table,.init table,.destroy_chat table,.delete_account table,.sessions table,.filter table,.linkfilter table,.notes table,.approve_waiting table,.del_confirm table,.profile table,.admin table,.backup table,.setup table{margin-left:auto;margin-right:auto;} ';
264 echo '.setup table table table,.admin table table table,.profile table table table{border-spacing:0px;margin-left:auto;margin-right:unset;width:unset;} ';
265 echo '.setup table table td,.backup #restoresubmit,.backup #backupsubmit,.admin table table td,.profile table table td,.login td+td,.alogin td+td{text-align:right;} ';
266 echo '.init td,.backup #restorecheck td,.admin #clean td,.admin #regnew td,.session td,.messages,.inbox,.approve_waiting td,.choose_messages,.greeting,.help,.login td,.alogin td{text-align:left;} ';
267 echo '.messages #chatters{max-height:100px;overflow-y:auto;} .messages #chatters a{text-decoration-line:none;} .messages #chatters table{border-spacing:0px;} ';
268 echo '.messages #chatters th,.messages #chatters td,.post #firstline{vertical-align:top;} ';
269 echo '.approve_waiting #action td:only-child,.help #backcredit,.login td:only-child,.alogin td:only-child,.init td:only-child{text-align:center;} .sessions td,.sessions th,.approve_waiting td,.approve_waiting th{padding: 5px;} ';
270 echo '.sessions td td{padding: 1px;} .messages #bottom_link{position:fixed;top:0.5em;right:0.5em;} .messages #top_link{position:fixed;bottom:0.5em;right:0.5em;} ';
271 echo '.post table,.controls table,.login table{border-spacing:0px;margin-left:auto;margin-right:auto;} .login table{border:2px solid;} .controls{overflow-y:none;} ';
272 echo '#manualrefresh{display:block;position:fixed;text-align:center;left:25%;width:50%;top:-200%;animation:timeout_messages ';
273 if(isset($U['refresh'])){
274 echo $U['refresh']+20;
275 }else{
276 echo '160';
277 }
278 echo 's forwards;z-index:2;background-color:#500000;border:2px solid #ff0000;} ';
279 echo '@keyframes timeout_messages{0%{top:-200%;} 99%{top:-200%;} 100%{top:0%;}} ';
280 echo '.notes textarea{height:80vh;width:80%;}';
281 echo '</style>';
282 if($init){
283 return;
284 }
285 $css=get_setting('css');
286 $coltxt=get_setting('coltxt');
287 if(!empty($U['bgcolour'])){
288 $colbg=$U['bgcolour'];
289 }else{
290 $colbg=get_setting('colbg');
291 }
292 //overwrite with custom css
293 echo "<style type=\"text/css\">body{background-color:#$colbg;color:#$coltxt;} $css</style>";
294}
295
296function print_end(){
297 echo '</body></html>';
298 exit;
299}
300
301function credit(){
302 return '<small><br><br><a target="_blank" href="https://github.com/DanWin/le-chat-php">LE CHAT-PHP - ' . VERSION . '</a></small>';
303}
304
305function meta_html(){
306 return '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><meta http-equiv="Pragma" content="no-cache"><meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate, max-age=0"><meta http-equiv="expires" content="0"><meta name="referrer" content="no-referrer">';
307}
308
309function form($action, $do=''){
310 global $language;
311 $form="<form action=\"$_SERVER[SCRIPT_NAME]\" enctype=\"multipart/form-data\" method=\"post\">".hidden('lang', $language).hidden('nc', substr(time(), -6)).hidden('action', $action);
312 if(!empty($_REQUEST['session'])){
313 $form.=hidden('session', $_REQUEST['session']);
314 }
315 if($do!==''){
316 $form.=hidden('do', $do);
317 }
318 return $form;
319}
320
321function form_target($target, $action, $do=''){
322 global $language;
323 $form="<form action=\"$_SERVER[SCRIPT_NAME]\" enctype=\"multipart/form-data\" method=\"post\" target=\"$target\">".hidden('lang', $language).hidden('nc', substr(time(), -6)).hidden('action', $action);
324 if(!empty($_REQUEST['session'])){
325 $form.=hidden('session', $_REQUEST['session']);
326 }
327 if($do!==''){
328 $form.=hidden('do', $do);
329 }
330 return $form;
331}
332
333function hidden($arg1='', $arg2=''){
334 return "<input type=\"hidden\" name=\"$arg1\" value=\"$arg2\">";
335}
336
337function submit($arg1='', $arg2=''){
338 return "<input type=\"submit\" value=\"$arg1\" $arg2>";
339}
340
341function thr(){
342 echo '<tr><td><hr></td></tr>';
343}
344
345function print_start($class='', $ref=0, $url=''){
346 global $I;
347 if(!empty($url)){
348 $url=str_replace('&', '&', $url);// Don't escape "&" in URLs here, it breaks some (older) browsers and js refresh!
349 header("Refresh: $ref; URL=$url");
350 }
351 echo '<!DOCTYPE html><html><head>'.meta_html();
352 if(!empty($url)){
353 echo "<meta http-equiv=\"Refresh\" content=\"$ref; URL=$url\">";
354 $ref+=5;//only use js if browser refresh stopped working
355 $ref*=1000;//js uses milliseconds
356 echo "<script type=\"text/javascript\">setTimeout(function(){window.location.replace(\"$url\");}, $ref);</script>";
357 }
358 if($class==='init'){
359 echo "<title>$I[init]</title>";
360 print_stylesheet(true);
361 }else{
362 echo '<title>'.get_setting('chatname').'</title>';
363 print_stylesheet();
364 }
365 echo "</head><body class=\"$class\">";
366 if($class!=='init' && ($externalcss=get_setting('externalcss'))!=''){
367 //external css - in body to make it non-renderblocking
368 echo "<link rel=\"stylesheet\" type=\"text/css\" href=\"$externalcss\">";
369 }
370}
371
372function send_redirect($url){
373 global $I;
374 $url=htmlspecialchars_decode(rawurldecode($url));
375 preg_match('~^(.*)://~u', $url, $match);
376 $url=preg_replace('~^(.*)://~u', '', $url);
377 $escaped=htmlspecialchars($url);
378 if(isset($match[1]) && ($match[1]==='http' || $match[1]==='https')){
379 print_start('redirect', 0, $match[0].$escaped);
380 echo "<p>$I[redirectto] <a href=\"$match[0]$escaped\">$match[0]$escaped</a>.</p>";
381 }else{
382 print_start('redirect');
383 if(!isset($match[0])){
384 $match[0]='';
385 }
386 echo "<p>$I[nonhttp] <a href=\"$match[0]$escaped\">$match[0]$escaped</a>.</p>";
387 echo "<p>$I[httpredir] <a href=\"http://$escaped\">http://$escaped</a>.</p>";
388 }
389 print_end();
390}
391
392function send_access_denied(){
393 global $I, $U;
394 header('HTTP/1.1 403 Forbidden');
395 print_start('access_denied');
396 echo "<h1>$I[accessdenied]</h1>".sprintf($I['loggedinas'], style_this(htmlspecialchars($U['nickname']), $U['style'])).'<br>';
397 echo form('logout');
398 if(!isset($_REQUEST['session'])){
399 echo hidden('session', $U['session']);
400 }
401 echo submit($I['logout'], 'id="exitbutton"')."</form>";
402 print_end();
403}
404
405function send_captcha(){
406 global $I, $db, $memcached;
407 $difficulty=(int) get_setting('captcha');
408 if($difficulty===0 || !extension_loaded('gd')){
409 return;
410 }
411 $captchachars=get_setting('captchachars');
412 $length=strlen($captchachars)-1;
413 $code='';
414 for($i=0;$i<5;++$i){
415 $code.=$captchachars[mt_rand(0, $length)];
416 }
417 $randid=mt_rand();
418 $time=time();
419 if(MEMCACHED){
420 $memcached->set(DBNAME . '-' . PREFIX . "captcha-$randid", $code, get_setting('captchatime'));
421 }else{
422 $stmt=$db->prepare('INSERT INTO ' . PREFIX . 'captcha (id, time, code) VALUES (?, ?, ?);');
423 $stmt->execute([$randid, $time, $code]);
424 }
425 echo "<tr id=\"captcha\"><td>$I[copy]<br>";
426 if($difficulty===1){
427 $im=imagecreatetruecolor(55, 24);
428 $bg=imagecolorallocate($im, 0, 0, 0);
429 $fg=imagecolorallocate($im, 255, 255, 255);
430 imagefill($im, 0, 0, $bg);
431 imagestring($im, 5, 5, 5, $code, $fg);
432 echo '<img width="55" height="24" src="data:image/gif;base64,';
433 }elseif($difficulty===2){
434 $im=imagecreatetruecolor(55, 24);
435 $bg=imagecolorallocate($im, 0, 0, 0);
436 $fg=imagecolorallocate($im, 255, 255, 255);
437 imagefill($im, 0, 0, $bg);
438 imagestring($im, 5, 5, 5, $code, $fg);
439 $line=imagecolorallocate($im, 255, 255, 255);
440 for($i=0;$i<2;++$i){
441 imageline($im, 0, mt_rand(0, 24), 55, mt_rand(0, 24), $line);
442 }
443 $dots=imagecolorallocate($im, 255, 255, 255);
444 for($i=0;$i<100;++$i){
445 imagesetpixel($im, mt_rand(0, 55), mt_rand(0, 24), $dots);
446 }
447 echo '<img width="55" height="24" src="data:image/gif;base64,';
448 }else{
449 $im=imagecreatetruecolor(150, 200);
450 $bg=imagecolorallocate($im, 0, 0, 0);
451 $fg=imagecolorallocate($im, 255, 255, 255);
452 imagefill($im, 0, 0, $bg);
453 $chars=[];
454 for($i=0;$i<10;++$i){
455 $found=false;
456 while(!$found){
457 $x=mt_rand(10, 140);
458 $y=mt_rand(10, 180);
459 $found=true;
460 foreach($chars as $char){
461 if($char['x']>=$x && ($char['x']-$x)<25){
462 $found=false;
463 }elseif($char['x']<$x && ($x-$char['x'])<25){
464 $found=false;
465 }
466 if(!$found){
467 if($char['y']>=$y && ($char['y']-$y)<25){
468 break;
469 }elseif($char['y']<$y && ($y-$char['y'])<25){
470 break;
471 }else{
472 $found=true;
473 }
474 }
475 }
476 }
477 $chars[]=['x', 'y'];
478 $chars[$i]['x']=$x;
479 $chars[$i]['y']=$y;
480 if($i<5){
481 imagechar($im, 5, $chars[$i]['x'], $chars[$i]['y'], $captchachars[mt_rand(0, $length)], $fg);
482 }else{
483 imagechar($im, 5, $chars[$i]['x'], $chars[$i]['y'], $code[$i-5], $fg);
484 }
485 }
486 $follow=imagecolorallocate($im, 200, 0, 0);
487 imagearc($im, $chars[5]['x']+4, $chars[5]['y']+8, 16, 16, 0, 360, $follow);
488 for($i=5;$i<9;++$i){
489 imageline($im, $chars[$i]['x']+4, $chars[$i]['y']+8, $chars[$i+1]['x']+4, $chars[$i+1]['y']+8, $follow);
490 }
491 $line=imagecolorallocate($im, 255, 255, 255);
492 for($i=0;$i<5;++$i){
493 imageline($im, 0, mt_rand(0, 200), 150, mt_rand(0, 200), $line);
494 }
495 $dots=imagecolorallocate($im, 255, 255, 255);
496 for($i=0;$i<1000;++$i){
497 imagesetpixel($im, mt_rand(0, 150), mt_rand(0, 200), $dots);
498 }
499 echo '<img width="150" height="200" src="data:image/gif;base64,';
500 }
501 ob_start();
502 imagegif($im);
503 imagedestroy($im);
504 echo base64_encode(ob_get_clean()).'">';
505 echo '</td><td>'.hidden('challenge', $randid).'<input type="text" name="captcha" size="15" autocomplete="off"></td></tr>';
506}
507
508function send_setup($C){
509 global $I, $U;
510 print_start('setup');
511 echo "<h2>$I[setup]</h2>".form('setup', 'save');
512 if(!isset($_REQUEST['session'])){
513 echo hidden('session', $U['session']);
514 }
515 echo '<table id="guestaccess">';
516 thr();
517 $ga=(int) get_setting('guestaccess');
518 echo "<tr><td><table><tr><th>$I[guestacc]</th><td>";
519 echo '<select name="guestaccess">';
520 echo '<option value="1"';
521 if($ga===1){
522 echo ' selected';
523 }
524 echo ">$I[guestallow]</option>";
525 echo '<option value="2"';
526 if($ga===2){
527 echo ' selected';
528 }
529 echo ">$I[guestwait]</option>";
530 echo '<option value="3"';
531 if($ga===3){
532 echo ' selected';
533 }
534 echo ">$I[adminallow]</option>";
535 echo '<option value="0"';
536 if($ga===0){
537 echo ' selected';
538 }
539 echo ">$I[guestdisallow]</option>";
540 echo '<option value="4"';
541 if($ga===4){
542 echo ' selected';
543 }
544 echo ">$I[disablechat]</option>";
545 echo '</select></td></tr></table></td></tr>';
546 thr();
547 $englobal=(int) get_setting('englobalpass');
548 echo "<tr><td><table id=\"globalpass\"><tr><th>$I[globalloginpass]</th><td>";
549 echo '<table>';
550 echo '<tr><td><select name="englobalpass">';
551 echo '<option value="0"';
552 if($englobal===0){
553 echo ' selected';
554 }
555 echo ">$I[disabled]</option>";
556 echo '<option value="1"';
557 if($englobal===1){
558 echo ' selected';
559 }
560 echo ">$I[enabled]</option>";
561 echo '<option value="2"';
562 if($englobal===2){
563 echo ' selected';
564 }
565 echo ">$I[onlyguests]</option>";
566 echo '</select></td><td> </td>';
567 echo '<td><input type="text" name="globalpass" value="'.htmlspecialchars(get_setting('globalpass')).'"></td></tr>';
568 echo '</table></td></tr></table></td></tr>';
569 thr();
570 $ga=(int) get_setting('guestreg');
571 echo "<tr><td><table id=\"guestreg\"><tr><th>$I[guestreg]</th><td>";
572 echo '<select name="guestreg">';
573 echo '<option value="0"';
574 if($ga===0){
575 echo ' selected';
576 }
577 echo ">$I[disabled]</option>";
578 echo '<option value="1"';
579 if($ga===1){
580 echo ' selected';
581 }
582 echo ">$I[assuguest]</option>";
583 echo '<option value="2"';
584 if($ga===2){
585 echo ' selected';
586 }
587 echo ">$I[asmember]</option>";
588 echo '</select></td></tr></table></td></tr>';
589 thr();
590 echo "<tr><td><table id=\"sysmessages\"><tr><th>$I[sysmessages]</th><td>";
591 echo '<table>';
592 foreach($C['msg_settings'] as $setting){
593 echo "<tr><td> $I[$setting]</td><td> <input type=\"text\" name=\"$setting\" value=\"".get_setting($setting).'"></td></tr>';
594 }
595 echo '</table></td></tr></table></td></tr>';
596 foreach($C['text_settings'] as $setting){
597 thr();
598 echo "<tr><td><table id=\"$setting\"><tr><th>".$I[$setting].'</th><td>';
599 echo "<input type=\"text\" name=\"$setting\" value=\"".htmlspecialchars(get_setting($setting)).'">';
600 echo '</td></tr></table></td></tr>';
601 }
602 foreach($C['colour_settings'] as $setting){
603 thr();
604 echo "<tr><td><table id=\"$setting\"><tr><th>".$I[$setting].'</th><td>';
605 echo "<input type=\"color\" name=\"$setting\" value=\"#".htmlspecialchars(get_setting($setting)).'">';
606 echo '</td></tr></table></td></tr>';
607 }
608 thr();
609 echo "<tr><td><table id=\"captcha\"><tr><th>$I[captcha]</th><td>";
610 echo '<table>';
611 if(!extension_loaded('gd')){
612 echo "<tr><td>$I[gdextrequired]</td></tr>";
613 }else{
614 echo '<tr><td><select name="dismemcaptcha">';
615 $dismemcaptcha=(bool) get_setting('dismemcaptcha');
616 echo '<option value="0"';
617 if(!$dismemcaptcha){
618 echo ' selected';
619 }
620 echo ">$I[enabled]</option>";
621 echo '<option value="1"';
622 if($dismemcaptcha){
623 echo ' selected';
624 }
625 echo ">$I[onlyguests]</option>";
626 echo '</select></td><td><select name="captcha">';
627 $captcha=(int) get_setting('captcha');
628 echo '<option value="0"';
629 if($captcha===0){
630 echo ' selected';
631 }
632 echo ">$I[disabled]</option>";
633 echo '<option value="1"';
634 if($captcha===1){
635 echo ' selected';
636 }
637 echo ">$I[simple]</option>";
638 echo '<option value="2"';
639 if($captcha===2){
640 echo ' selected';
641 }
642 echo ">$I[moderate]</option>";
643 echo '<option value="3"';
644 if($captcha===3){
645 echo ' selected';
646 }
647 echo ">$I[extreme]</option>";
648 echo '</select></td></tr>';
649 }
650 echo '</table></td></tr></table></td></tr>';
651 thr();
652 echo "<tr><td><table id=\"defaulttz\"><tr><th>$I[defaulttz]</th><td>";
653 echo "<select name=\"defaulttz\">";
654 $tzs=timezone_identifiers_list();
655 $defaulttz=get_setting('defaulttz');
656 foreach($tzs as $tz){
657 echo "<option value=\"$tz\"";
658 if($defaulttz==$tz){
659 echo ' selected';
660 }
661 echo ">$tz</option>";
662 }
663 echo '</select>';
664 echo '</td></tr></table></td></tr>';
665 foreach($C['textarea_settings'] as $setting){
666 thr();
667 echo "<tr><td><table id=\"$setting\"><tr><th>".$I[$setting].'</th><td>';
668 echo "<textarea name=\"$setting\" rows=\"4\" cols=\"60\">".htmlspecialchars(get_setting($setting)).'</textarea>';
669 echo '</td></tr></table></td></tr>';
670 }
671 foreach($C['number_settings'] as $setting){
672 thr();
673 echo "<tr><td><table id=\"$setting\"><tr><th>".$I[$setting].'</th><td>';
674 echo "<input type=\"number\" name=\"$setting\" value=\"".htmlspecialchars(get_setting($setting)).'">';
675 echo '</td></tr></table></td></tr>';
676 }
677 foreach($C['bool_settings'] as $setting){
678 thr();
679 echo "<tr><td><table id=\"$setting\"><tr><th>".$I[$setting].'</th><td>';
680 echo "<select name=\"$setting\">";
681 $value=(bool) get_setting($setting);
682 echo '<option value="0"';
683 if(!$value){
684 echo ' selected';
685 }
686 echo ">$I[disabled]</option>";
687 echo '<option value="1"';
688 if($value){
689 echo ' selected';
690 }
691 echo ">$I[enabled]</option>";
692 echo '</select></td></tr>';
693 echo '</table></td></tr>';
694 }
695 thr();
696 echo '<tr><td>'.submit($I['apply']).'</td></tr></table></form><br>';
697 if($U['status']==8){
698 echo '<table id="actions"><tr><td>';
699 echo form('setup', 'backup');
700 if(!isset($_REQUEST['session'])){
701 echo hidden('session', $U['session']);
702 }
703 echo submit($I['backuprestore']).'</form></td><td>';
704 echo form('setup', 'destroy');
705 if(!isset($_REQUEST['session'])){
706 echo hidden('session', $U['session']);
707 }
708 echo submit($I['destroy'], 'class="delbutton"').'</form></td></tr></table><br>';
709 }
710 echo form_target('_parent', 'logout');
711 if(!isset($_REQUEST['session'])){
712 echo hidden('session', $U['session']);
713 }
714 echo submit($I['logout'], 'id="exitbutton"').'</form>'.credit();
715 print_end();
716}
717
718function restore_backup($C){
719 global $db, $memcached;
720 if(!extension_loaded('json')){
721 return;
722 }
723 $code=json_decode($_REQUEST['restore'], true);
724 if(isset($_REQUEST['settings'])){
725 foreach($C['settings'] as $setting){
726 if(isset($code['settings'][$setting])){
727 update_setting($setting, $code['settings'][$setting]);
728 }
729 }
730 }
731 if(isset($_REQUEST['filter']) && (isset($code['filters']) || isset($code['linkfilters']))){
732 $db->exec('DELETE FROM ' . PREFIX . 'filter;');
733 $db->exec('DELETE FROM ' . PREFIX . 'linkfilter;');
734 $stmt=$db->prepare('INSERT INTO ' . PREFIX . 'filter (filtermatch, filterreplace, allowinpm, regex, kick, cs) VALUES (?, ?, ?, ?, ?, ?);');
735 foreach($code['filters'] as $filter){
736 if(!isset($filter['cs'])){
737 $filter['cs']=0;
738 }
739 $stmt->execute([$filter['match'], $filter['replace'], $filter['allowinpm'], $filter['regex'], $filter['kick'], $filter['cs']]);
740 }
741 $stmt=$db->prepare('INSERT INTO ' . PREFIX . 'linkfilter (filtermatch, filterreplace, regex) VALUES (?, ?, ?);');
742 foreach($code['linkfilters'] as $filter){
743 $stmt->execute([$filter['match'], $filter['replace'], $filter['regex']]);
744 }
745 if(MEMCACHED){
746 $memcached->delete(DBNAME . '-' . PREFIX . 'filter');
747 $memcached->delete(DBNAME . '-' . PREFIX . 'linkfilter');
748 }
749 }
750 if(isset($_REQUEST['members']) && isset($code['members'])){
751 $db->exec('DELETE FROM ' . PREFIX . 'inbox;');
752 $db->exec('DELETE FROM ' . PREFIX . 'members;');
753 $stmt=$db->prepare('INSERT INTO ' . PREFIX . 'members (nickname, passhash, status, refresh, bgcolour, regedby, lastlogin, timestamps, embed, incognito, style, nocache, tz, eninbox, sortupdown, hidechatters, nocache_old) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);');
754 foreach($code['members'] as $member){
755 $new_settings=['nocache', 'tz', 'eninbox', 'sortupdown', 'hidechatters', 'nocache_old'];
756 foreach($new_settings as $setting){
757 if(!isset($member[$setting])){
758 $member[$setting]=0;
759 }
760 }
761 $stmt->execute([$member['nickname'], $member['passhash'], $member['status'], $member['refresh'], $member['bgcolour'], $member['regedby'], $member['lastlogin'], $member['timestamps'], $member['embed'], $member['incognito'], $member['style'], $member['nocache'], $member['tz'], $member['eninbox'], $member['sortupdown'], $member['hidechatters'], $member['nocache_old']]);
762 }
763 }
764 if(isset($_REQUEST['notes']) && isset($code['notes'])){
765 $db->exec('DELETE FROM ' . PREFIX . 'notes;');
766 $stmt=$db->prepare('INSERT INTO ' . PREFIX . 'notes (type, lastedited, editedby, text) VALUES (?, ?, ?, ?);');
767 foreach($code['notes'] as $note){
768 if($note['type']==='admin'){
769 $note['type']=0;
770 }elseif($note['type']==='staff'){
771 $note['type']=1;
772 }
773 if(MSGENCRYPTED){
774 $note['text']=openssl_encrypt($note['text'], 'aes-256-cbc', ENCRYPTKEY, 0, '1234567890123456');
775 }
776 $stmt->execute([$note['type'], $note['lastedited'], $note['editedby'], $note['text']]);
777 }
778 }
779}
780
781function send_backup($C){
782 global $I, $db;
783 $code=[];
784 if($_REQUEST['do']==='backup'){
785 if(isset($_REQUEST['settings'])){
786 foreach($C['settings'] as $setting){
787 $code['settings'][$setting]=get_setting($setting);
788 }
789 }
790 if(isset($_REQUEST['filter'])){
791 $result=$db->query('SELECT * FROM ' . PREFIX . 'filter;');
792 while($filter=$result->fetch(PDO::FETCH_ASSOC)){
793 $code['filters'][]=['match'=>$filter['filtermatch'], 'replace'=>$filter['filterreplace'], 'allowinpm'=>$filter['allowinpm'], 'regex'=>$filter['regex'], 'kick'=>$filter['kick'], 'cs'=>$filter['cs']];
794 }
795 $result=$db->query('SELECT * FROM ' . PREFIX . 'linkfilter;');
796 while($filter=$result->fetch(PDO::FETCH_ASSOC)){
797 $code['linkfilters'][]=['match'=>$filter['filtermatch'], 'replace'=>$filter['filterreplace'], 'regex'=>$filter['regex']];
798 }
799 }
800 if(isset($_REQUEST['members'])){
801 $result=$db->query('SELECT * FROM ' . PREFIX . 'members;');
802 while($member=$result->fetch(PDO::FETCH_ASSOC)){
803 $code['members'][]=$member;
804 }
805 }
806 if(isset($_REQUEST['notes'])){
807 $result=$db->query('SELECT * FROM ' . PREFIX . "notes;");
808 while($note=$result->fetch(PDO::FETCH_ASSOC)){
809 if(MSGENCRYPTED){
810 $note['text']=openssl_decrypt($note['text'], 'aes-256-cbc', ENCRYPTKEY, 0, '1234567890123456');
811 }
812 $code['notes'][]=$note;
813 }
814 }
815 }
816 if(isset($_REQUEST['settings'])){
817 $chksettings=' checked';
818 }else{
819 $chksettings='';
820 }
821 if(isset($_REQUEST['filter'])){
822 $chkfilters=' checked';
823 }else{
824 $chkfilters='';
825 }
826 if(isset($_REQUEST['members'])){
827 $chkmembers=' checked';
828 }else{
829 $chkmembers='';
830 }
831 if(isset($_REQUEST['notes'])){
832 $chknotes=' checked';
833 }else{
834 $chknotes='';
835 }
836 print_start('backup');
837 echo "<h2>$I[backuprestore]</h2><table>";
838 thr();
839 if(!extension_loaded('json')){
840 echo "<tr><td>$I[jsonextrequired]</td></tr>";
841 }else{
842 echo '<tr><td>'.form('setup', 'backup');
843 echo '<table id="backup"><tr><td id="backupcheck">';
844 echo "<label><input type=\"checkbox\" name=\"settings\" id=\"backupsettings\" value=\"1\"$chksettings>$I[settings]</label>";
845 echo "<label><input type=\"checkbox\" name=\"filter\" id=\"backupfilter\" value=\"1\"$chkfilters>$I[filter]</label>";
846 echo "<label><input type=\"checkbox\" name=\"members\" id=\"backupmembers\" value=\"1\"$chkmembers>$I[members]</label>";
847 echo "<label><input type=\"checkbox\" name=\"notes\" id=\"backupnotes\" value=\"1\"$chknotes>$I[notes]</label>";
848 echo '</td><td id="backupsubmit">'.submit($I['backup']).'</td></tr></table></form></td></tr>';
849 thr();
850 echo '<tr><td>'.form('setup', 'restore');
851 echo '<table id="restore">';
852 echo "<tr><td colspan=\"2\"><textarea name=\"restore\" rows=\"4\" cols=\"60\">".htmlspecialchars(json_encode($code)).'</textarea></td></tr>';
853 echo "<tr><td id=\"restorecheck\"><label><input type=\"checkbox\" name=\"settings\" id=\"restoresettings\" value=\"1\"$chksettings>$I[settings]</label>";
854 echo "<label><input type=\"checkbox\" name=\"filter\" id=\"restorefilter\" value=\"1\"$chkfilters>$I[filter]</label>";
855 echo "<label><input type=\"checkbox\" name=\"members\" id=\"restoremembers\" value=\"1\"$chkmembers>$I[members]</label>";
856 echo "<label><input type=\"checkbox\" name=\"notes\" id=\"restorenotes\" value=\"1\"$chknotes>$I[notes]</label>";
857 echo '</td><td id="restoresubmit">'.submit($I['restore']).'</td></tr></table>';
858 echo '</form></td></tr>';
859 }
860 thr();
861 echo '<tr><td>'.form('setup').submit($I['initgosetup'], 'class="backbutton"')."</form></tr></td>";
862 echo '</table>';
863 print_end();
864}
865
866function send_destroy_chat(){
867 global $I;
868 print_start('destroy_chat');
869 echo "<table><tr><td colspan=\"2\">$I[confirm]</td></tr><tr><td>";
870 echo form_target('_parent', 'setup', 'destroy').hidden('confirm', 'yes').submit($I['yes'], 'class="delbutton"').'</form></td><td>';
871 echo form('setup').submit($I['no'], 'class="backbutton"').'</form></td><tr></table>';
872 print_end();
873}
874
875function send_delete_account(){
876 global $I;
877 print_start('delete_account');
878 echo "<table><tr><td colspan=\"2\">$I[confirm]</td></tr><tr><td>";
879 echo form('profile', 'delete').hidden('confirm', 'yes').submit($I['yes'], 'class="delbutton"').'</form></td><td>';
880 echo form('profile').submit($I['no'], 'class="backbutton"').'</form></td><tr></table>';
881 print_end();
882}
883
884function send_init(){
885 global $I, $L;
886 print_start('init');
887 echo "<h2>$I[init]</h2>";
888 echo form('init')."<table><tr><td><h3>$I[sulogin]</h3><table>";
889 echo "<tr><td>$I[sunick]</td><td><input type=\"text\" name=\"sunick\" size=\"15\"></td></tr>";
890 echo "<tr><td>$I[supass]</td><td><input type=\"password\" name=\"supass\" size=\"15\"></td></tr>";
891 echo "<tr><td>$I[suconfirm]</td><td><input type=\"password\" name=\"supassc\" size=\"15\"></td></tr>";
892 echo '</table></td></tr><tr><td><br>'.submit($I['initbtn']).'</td></tr></table></form>';
893 echo "<p id=\"changelang\">$I[changelang]";
894 foreach($L as $lang=>$name){
895 echo " <a href=\"$_SERVER[SCRIPT_NAME]?action=setup&lang=$lang\">$name</a>";
896 }
897 echo '</p>'.credit();
898 print_end();
899}
900
901function send_update($msg){
902 global $I;
903 print_start('update');
904 echo "<h2>$I[dbupdate]</h2><br>".form('setup').submit($I['initgosetup'])."</form>$msg<br>".credit();
905 print_end();
906}
907
908function send_alogin(){
909 global $I, $L;
910 print_start('alogin');
911 echo form('setup').'<table>';
912 echo "<tr><td>$I[nick]</td><td><input type=\"text\" name=\"nick\" size=\"15\" autofocus></td></tr>";
913 echo "<tr><td>$I[pass]</td><td><input type=\"password\" name=\"pass\" size=\"15\"></td></tr>";
914 send_captcha();
915 echo '<tr><td colspan="2">'.submit($I['login']).'</td></tr></table></form>';
916 echo "<p id=\"changelang\">$I[changelang]";
917 foreach($L as $lang=>$name){
918 echo " <a href=\"$_SERVER[SCRIPT_NAME]?action=setup&lang=$lang\">$name</a>";
919 }
920 echo '</p>'.credit();
921 print_end();
922}
923
924function send_admin($arg=''){
925 global $I, $U, $db;
926 $ga=(int) get_setting('guestaccess');
927 print_start('admin');
928 $chlist="<select name=\"name[]\" size=\"5\" multiple><option value=\"\">$I[choose]</option>";
929 $chlist.="<option value=\"s &\">$I[allguests]</option>";
930 $users=[];
931 $stmt=$db->query('SELECT nickname, style, status FROM ' . PREFIX . 'sessions WHERE entry!=0 AND status>0 ORDER BY LOWER(nickname);');
932 while($user=$stmt->fetch(PDO::FETCH_NUM)){
933 $users[]=[htmlspecialchars($user[0]), $user[1], $user[2]];
934 }
935 foreach($users as $user){
936 if($user[2]<$U['status']){
937 $chlist.="<option value=\"$user[0]\" style=\"$user[1]\">$user[0]</option>";
938 }
939 }
940 $chlist.='</select>';
941 echo "<h2>$I[admfunc]</h2><i>$arg</i><table>";
942 if($U['status']>=7){
943 thr();
944 echo '<tr><td>'.form_target('view', 'setup').submit($I['initgosetup']).'</form></td></tr>';
945 }
946 thr();
947 echo "<tr><td><table id=\"clean\"><tr><th>$I[cleanmsgs]</th><td>";
948 echo form('admin', 'clean');
949 echo '<table><tr><td><label><input type="radio" name="what" id="room" value="room">';
950 echo "$I[room]</label></td><td> </td><td><label><input type=\"radio\" name=\"what\" id=\"choose\" value=\"choose\" checked>";
951 echo "$I[selection]</label></td><td> </td></tr><tr><td colspan=\"3\"><label><input type=\"radio\" name=\"what\" id=\"nick\" value=\"nick\">";
952 echo "$I[cleannick]</label> <select name=\"nickname\" size=\"1\"><option value=\"\">$I[choose]</option>";
953 $stmt=$db->prepare('SELECT poster FROM ' . PREFIX . "messages WHERE delstatus<? AND poster!='' GROUP BY poster;");
954 $stmt->execute([$U['status']]);
955 while($nick=$stmt->fetch(PDO::FETCH_NUM)){
956 echo '<option value="'.htmlspecialchars($nick[0]).'">'.htmlspecialchars($nick[0]).'</option>';
957 }
958 echo '</select></td><td>';
959 echo submit($I['clean'], 'class="delbutton"').'</td></tr></table></form></td></tr></table></td></tr>';
960 thr();
961 echo '<tr><td><table id="kick"><tr><th>'.sprintf($I['kickchat'], get_setting('kickpenalty')).'</th></tr><tr><td>';
962 echo form('admin', 'kick');
963 echo "<table><tr><td>$I[kickreason]</td><td><input type=\"text\" name=\"kickmessage\" size=\"30\"></td><td> </td></tr>";
964 echo "<tr><td><label><input type=\"checkbox\" name=\"what\" value=\"purge\" id=\"purge\">$I[kickpurge]</label></td><td>$chlist</td><td>";
965 echo submit($I['kick']).'</td></tr></table></form></td></tr></table></td></tr>';
966 thr();
967 echo "<tr><td><table id=\"logout\"><tr><th>$I[logoutinact]</th><td>";
968 echo form('admin', 'logout');
969 echo "<table><tr><td>$chlist</td><td>";
970 echo submit($I['logout']).'</td></tr></table></form></td></tr></table></td></tr>';
971 $views=['sessions', 'filter', 'linkfilter'];
972 foreach($views as $view){
973 thr();
974 echo "<tr><td><table id=\"$view\"><tr><th>".$I[$view].'</th><td>';
975 echo form('admin', $view);
976 echo submit($I['view']).'</form></td></tr></table></td></tr>';
977 }
978 thr();
979 echo "<tr><td><table id=\"topic\"><tr><th>$I[topic]</th><td>";
980 echo form('admin', 'topic');
981 echo '<table><tr><td><input type="text" name="topic" size="20" value="'.get_setting('topic').'"></td><td>';
982 echo submit($I['change']).'</td></tr></table></form></td></tr></table></td></tr>';
983 thr();
984 echo "<tr><td><table id=\"guestaccess\"><tr><th>$I[guestacc]</th><td>";
985 echo form('admin', 'guestaccess');
986 echo '<table>';
987 echo '<tr><td><select name="guestaccess">';
988 echo '<option value="1"';
989 if($ga===1){
990 echo ' selected';
991 }
992 echo ">$I[guestallow]</option>";
993 echo '<option value="2"';
994 if($ga===2){
995 echo ' selected';
996 }
997 echo ">$I[guestwait]</option>";
998 echo '<option value="3"';
999 if($ga===3){
1000 echo ' selected';
1001 }
1002 echo ">$I[adminallow]</option>";
1003 echo '<option value="0"';
1004 if($ga===0){
1005 echo ' selected';
1006 }
1007 echo ">$I[guestdisallow]</option>";
1008 if($ga===4){
1009 echo '<option value="4" selected';
1010 echo ">$I[disablechat]</option>";
1011 }
1012 echo '</select></td><td>'.submit($I['change']).'</td></tr></table></form></td></tr></table></td></tr>';
1013 thr();
1014 if(get_setting('suguests')){
1015 echo "<tr><td><table id=\"suguests\"><tr><th>$I[addsuguest]</th><td>";
1016 echo form('admin', 'superguest');
1017 echo "<table><tr><td><select name=\"name\" size=\"1\"><option value=\"\">$I[choose]</option>";
1018 foreach($users as $user){
1019 if($user[2]==1){
1020 echo "<option value=\"$user[0]\" style=\"$user[1]\">$user[0]</option>";
1021 }
1022 }
1023 echo '</select></td><td>'.submit($I['register']).'</td></tr></table></form></td></tr></table></td></tr>';
1024 thr();
1025 }
1026 if($U['status']>=7){
1027 echo "<tr><td><table id=\"status\"><tr><th>$I[admmembers]</th><td>";
1028 echo form('admin', 'status');
1029 echo "<table><td><select name=\"name\" size=\"1\"><option value=\"\">$I[choose]</option>";
1030 $members=[];
1031 $result=$db->query('SELECT nickname, style, status FROM ' . PREFIX . 'members ORDER BY LOWER(nickname);');
1032 while($temp=$result->fetch(PDO::FETCH_NUM)){
1033 $members[]=[htmlspecialchars($temp[0]), $temp[1], $temp[2]];
1034 }
1035 foreach($members as $member){
1036 echo "<option value=\"$member[0]\" style=\"$member[1]\">$member[0]";
1037 if($member[2]==0){
1038 echo ' (!)';
1039 }elseif($member[2]==2){
1040 echo ' (G)';
1041 }elseif($member[2]==3){
1042 }elseif($member[2]==5){
1043 echo ' (M)';
1044 }elseif($member[2]==6){
1045 echo ' (SM)';
1046 }elseif($member[2]==7){
1047 echo ' (A)';
1048 }else{
1049 echo ' (SA)';
1050 }
1051 echo '</option>';
1052 }
1053 echo "</select><select name=\"set\" size=\"1\"><option value=\"\">$I[choose]</option><option value=\"-\">$I[memdel]</option><option value=\"0\">$I[memdeny]</option>";
1054 if(get_setting('suguests')){
1055 echo "<option value=\"2\">$I[memsuguest]</option>";
1056 }
1057 echo "<option value=\"3\">$I[memreg]</option>";
1058 echo "<option value=\"5\">$I[memmod]</option>";
1059 echo "<option value=\"6\">$I[memsumod]</option>";
1060 if($U['status']>=8){
1061 echo "<option value=\"7\">$I[memadm]</option>";
1062 }
1063 echo '</select></td><td>'.submit($I['change']).'</td></tr></table></form></td></tr></table></td></tr>';
1064 thr();
1065 echo "<tr><td><table id=\"passreset\"><tr><th>$I[passreset]</th><td>";
1066 echo form('admin', 'passreset');
1067 echo "<table><td><select name=\"name\" size=\"1\"><option value=\"\">$I[choose]</option>";
1068 foreach($members as $member){
1069 echo "<option value=\"$member[0]\" style=\"$member[1]\">$member[0]</option>";
1070 }
1071 echo '</select></td><td><input type="password" name="pass"></td><td>'.submit($I['change']).'</td></tr></table></form></td></tr></table></td></tr>';
1072 thr();
1073 echo "<tr><td><table id=\"register\"><tr><th>$I[regguest]</th><td>";
1074 echo form('admin', 'register');
1075 echo "<table><tr><td><select name=\"name\" size=\"1\"><option value=\"\">$I[choose]</option>";
1076 foreach($users as $user){
1077 if($user[2]==1){
1078 echo "<option value=\"$user[0]\" style=\"$user[1]\">$user[0]</option>";
1079 }
1080 }
1081 echo '</select></td><td>'.submit($I['register']).'</td></tr></table></form></td></tr></table></td></tr>';
1082 thr();
1083 echo "<tr><td><table id=\"regnew\"><tr><th>$I[regmem]</th></tr><tr><td>";
1084 echo form('admin', 'regnew');
1085 echo "<table><tr><td>$I[nick]</td><td> </td><td><input type=\"text\" name=\"name\" size=\"20\"></td><td> </td></tr>";
1086 echo "<tr><td>$I[pass]</td><td> </td><td><input type=\"password\" name=\"pass\" size=\"20\"></td><td>";
1087 echo submit($I['register']).'</td></tr></table></form></td></tr></table></td></tr>';
1088 thr();
1089 }
1090 echo "</table><br>";
1091 echo form('admin').submit($I['reload']).'</form>';
1092 print_end();
1093}
1094
1095function send_sessions(){
1096 global $I, $U, $db;
1097 $stmt=$db->prepare('SELECT nickname, style, lastpost, status, useragent, ip FROM ' . PREFIX . 'sessions WHERE entry!=0 AND (incognito=0 OR status<? OR nickname=?) ORDER BY status DESC, lastpost DESC;');
1098 $stmt->execute([$U['status'], $U['nickname']]);
1099 if(!$lines=$stmt->fetchAll(PDO::FETCH_ASSOC)){
1100 $lines=[];
1101 }
1102 print_start('sessions');
1103 echo "<h1>$I[sessact]</h1><table>";
1104 echo "<tr><th>$I[sessnick]</th><th>$I[sesstimeout]</th><th>$I[sessua]</th>";
1105 $trackip=(bool) get_setting('trackip');
1106 $memexpire=(int) get_setting('memberexpire');
1107 $guestexpire=(int) get_setting('guestexpire');
1108 if($trackip) echo "<th>$I[sesip]</th>";
1109 echo "<th>$I[actions]</th></tr>";
1110 foreach($lines as $temp){
1111 if($temp['status']==0){
1112 $s=' (K)';
1113 }elseif($temp['status']<=2){
1114 $s=' (G)';
1115 }elseif($temp['status']==3){
1116 $s='';
1117 }elseif($temp['status']==5){
1118 $s=' (M)';
1119 }elseif($temp['status']==6){
1120 $s=' (SM)';
1121 }elseif($temp['status']==7){
1122 $s=' (A)';
1123 }else{
1124 $s=' (SA)';
1125 }
1126 echo '<tr><td class="nickname">'.style_this(htmlspecialchars($temp['nickname']).$s, $temp['style']).'</td><td class="timeout">';
1127 if($temp['status']>2){
1128 get_timeout($temp['lastpost'], $memexpire);
1129 }else{
1130 get_timeout($temp['lastpost'], $guestexpire);
1131 }
1132 echo '</td>';
1133 if($U['status']>$temp['status'] || $U['nickname']===$temp['nickname']){
1134 echo "<td class=\"ua\">$temp[useragent]</td>";
1135 if($trackip){
1136 echo "<td class=\"ip\">$temp[ip]</td>";
1137 }
1138 echo '<td class="action">';
1139 if($temp['nickname']!==$U['nickname']){
1140 echo '<table><tr>';
1141 if($temp['status']!=0){
1142 echo '<td>';
1143 echo form('admin', 'sessions');
1144 echo hidden('kick', '1').hidden('nick', htmlspecialchars($temp['nickname'])).submit($I['kick']).'</form>';
1145 echo '</td>';
1146 }
1147 echo '<td>';
1148 echo form('admin', 'sessions');
1149 echo hidden('logout', '1').hidden('nick', htmlspecialchars($temp['nickname'])).submit($temp['status']==0 ? $I['unban'] : $I['logout']).'</form>';
1150 echo '</td></tr></table>';
1151 }else{
1152 echo '-';
1153 }
1154 echo '</td></tr>';
1155 }else{
1156 echo '<td class="ua">-</td>';
1157 if($trackip){
1158 echo '<td class="ip">-</td>';
1159 }
1160 echo '<td class="action">-</td></tr>';
1161 }
1162 }
1163 echo "</table><br>";
1164 echo form('admin', 'sessions').submit($I['reload']).'</form>';
1165 print_end();
1166}
1167
1168function check_filter_match(&$reg){
1169 global $I;
1170 $_REQUEST['match']=htmlspecialchars($_REQUEST['match']);
1171 if(isset($_REQUEST['regex']) && $_REQUEST['regex']==1){
1172 if(!valid_regex($_REQUEST['match'])){
1173 return "$I[incorregex]<br>$I[prevmatch]: $_REQUEST[match]";
1174 }
1175 $reg=1;
1176 }else{
1177 $_REQUEST['match']=preg_replace('/([^\w\d])/u', "\\\\$1", $_REQUEST['match']);
1178 $reg=0;
1179 }
1180 if(mb_strlen($_REQUEST['match'])>255){
1181 return "$I[matchtoolong]<br>$I[prevmatch]: $_REQUEST[match]";
1182 }
1183 return false;
1184}
1185
1186function manage_filter(){
1187 global $db, $memcached;
1188 if(isset($_REQUEST['id'])){
1189 $reg=0;
1190 if($tmp=check_filter_match($reg)){
1191 return $tmp;
1192 }
1193 if(isset($_REQUEST['allowinpm']) && $_REQUEST['allowinpm']==1){
1194 $pm=1;
1195 }else{
1196 $pm=0;
1197 }
1198 if(isset($_REQUEST['kick']) && $_REQUEST['kick']==1){
1199 $kick=1;
1200 }else{
1201 $kick=0;
1202 }
1203 if(isset($_REQUEST['cs']) && $_REQUEST['cs']==1){
1204 $cs=1;
1205 }else{
1206 $cs=0;
1207 }
1208 if(preg_match('/^[0-9]+$/', $_REQUEST['id'])){
1209 if(empty($_REQUEST['match'])){
1210 $stmt=$db->prepare('DELETE FROM ' . PREFIX . 'filter WHERE id=?;');
1211 $stmt->execute([$_REQUEST['id']]);
1212 }else{
1213 $stmt=$db->prepare('UPDATE ' . PREFIX . 'filter SET filtermatch=?, filterreplace=?, allowinpm=?, regex=?, kick=?, cs=? WHERE id=?;');
1214 $stmt->execute([$_REQUEST['match'], $_REQUEST['replace'], $pm, $reg, $kick, $cs, $_REQUEST['id']]);
1215 }
1216 }elseif($_REQUEST['id']==='+'){
1217 $stmt=$db->prepare('INSERT INTO ' . PREFIX . 'filter (filtermatch, filterreplace, allowinpm, regex, kick, cs) VALUES (?, ?, ?, ?, ?, ?);');
1218 $stmt->execute([$_REQUEST['match'], $_REQUEST['replace'], $pm, $reg, $kick, $cs]);
1219 }
1220 if(MEMCACHED){
1221 $memcached->delete(DBNAME . '-' . PREFIX . 'filter');
1222 }
1223 }
1224}
1225
1226function manage_linkfilter(){
1227 global $db, $memcached;
1228 if(isset($_REQUEST['id'])){
1229 $reg=0;
1230 if($tmp=check_filter_match($reg)){
1231 return $tmp;
1232 }
1233 if(preg_match('/^[0-9]+$/', $_REQUEST['id'])){
1234 if(empty($_REQUEST['match'])){
1235 $stmt=$db->prepare('DELETE FROM ' . PREFIX . 'linkfilter WHERE id=?;');
1236 $stmt->execute([$_REQUEST['id']]);
1237 }else{
1238 $stmt=$db->prepare('UPDATE ' . PREFIX . 'linkfilter SET filtermatch=?, filterreplace=?, regex=? WHERE id=?;');
1239 $stmt->execute([$_REQUEST['match'], $_REQUEST['replace'], $reg, $_REQUEST['id']]);
1240 }
1241 }elseif($_REQUEST['id']==='+'){
1242 $stmt=$db->prepare('INSERT INTO ' . PREFIX . 'linkfilter (filtermatch, filterreplace, regex) VALUES (?, ?, ?);');
1243 $stmt->execute([$_REQUEST['match'], $_REQUEST['replace'], $reg]);
1244 }
1245 if(MEMCACHED){
1246 $memcached->delete(DBNAME . '-' . PREFIX . 'linkfilter');
1247 }
1248 }
1249}
1250
1251function get_filters(){
1252 global $db, $memcached;
1253 if(MEMCACHED){
1254 $filters=$memcached->get(DBNAME . '-' . PREFIX . 'filter');
1255 }
1256 if(!MEMCACHED || $memcached->getResultCode()!==Memcached::RES_SUCCESS){
1257 $filters=[];
1258 $result=$db->query('SELECT id, filtermatch, filterreplace, allowinpm, regex, kick, cs FROM ' . PREFIX . 'filter;');
1259 while($filter=$result->fetch(PDO::FETCH_ASSOC)){
1260 $filters[]=['id'=>$filter['id'], 'match'=>$filter['filtermatch'], 'replace'=>$filter['filterreplace'], 'allowinpm'=>$filter['allowinpm'], 'regex'=>$filter['regex'], 'kick'=>$filter['kick'], 'cs'=>$filter['cs']];
1261 }
1262 if(MEMCACHED){
1263 $memcached->set(DBNAME . '-' . PREFIX . 'filter', $filters);
1264 }
1265 }
1266 return $filters;
1267}
1268
1269function get_linkfilters(){
1270 global $db, $memcached;
1271 if(MEMCACHED){
1272 $filters=$memcached->get(DBNAME . '-' . PREFIX . 'linkfilter');
1273 }
1274 if(!MEMCACHED || $memcached->getResultCode()!==Memcached::RES_SUCCESS){
1275 $filters=[];
1276 $result=$db->query('SELECT id, filtermatch, filterreplace, regex FROM ' . PREFIX . 'linkfilter;');
1277 while($filter=$result->fetch(PDO::FETCH_ASSOC)){
1278 $filters[]=['id'=>$filter['id'], 'match'=>$filter['filtermatch'], 'replace'=>$filter['filterreplace'], 'regex'=>$filter['regex']];
1279 }
1280 if(MEMCACHED){
1281 $memcached->set(DBNAME . '-' . PREFIX . 'linkfilter', $filters);
1282 }
1283 }
1284 return $filters;
1285}
1286
1287function send_filter($arg=''){
1288 global $I, $U;
1289 print_start('filter');
1290 echo "<h2>$I[filter]</h2><i>$arg</i><table>";
1291 thr();
1292 echo '<tr><th><table style="width:100%;"><tr>';
1293 echo "<td style=\"width:8em;\">$I[fid]</td>";
1294 echo "<td style=\"width:12em;\">$I[match]</td>";
1295 echo "<td style=\"width:12em;\">$I[replace]</td>";
1296 echo "<td style=\"width:9em;\">$I[allowpm]</td>";
1297 echo "<td style=\"width:5em;\">$I[regex]</td>";
1298 echo "<td style=\"width:5em;\">$I[kick]</td>";
1299 echo "<td style=\"width:5em;\">$I[cs]</td>";
1300 echo "<td style=\"width:5em;\">$I[apply]</td>";
1301 echo '</tr></table></th></tr>';
1302 $filters=get_filters();
1303 foreach($filters as $filter){
1304 if($filter['allowinpm']==1){
1305 $check=' checked';
1306 }else{
1307 $check='';
1308 }
1309 if($filter['regex']==1){
1310 $checked=' checked';
1311 }else{
1312 $checked='';
1313 $filter['match']=preg_replace('/(\\\\(.))/u', "$2", $filter['match']);
1314 }
1315 if($filter['kick']==1){
1316 $checkedk=' checked';
1317 }else{
1318 $checkedk='';
1319 }
1320 if($filter['cs']==1){
1321 $checkedcs=' checked';
1322 }else{
1323 $checkedcs='';
1324 }
1325 echo '<tr><td>';
1326 echo form('admin', 'filter').hidden('id', $filter['id']);
1327 echo "<table style=\"width:100%;\"><tr><th style=\"width:8em;\">$I[filter] $filter[id]:</th>";
1328 echo "<td style=\"width:12em;\"><input type=\"text\" name=\"match\" value=\"$filter[match]\" size=\"20\" style=\"$U[style]\"></td>";
1329 echo '<td style="width:12em;"><input type="text" name="replace" value="'.htmlspecialchars($filter['replace'])."\" size=\"20\" style=\"$U[style]\"></td>";
1330 echo "<td style=\"width:9em;\"><label><input type=\"checkbox\" name=\"allowinpm\" value=\"1\"$check>$I[allowpm]</label></td>";
1331 echo "<td style=\"width:5em;\"><label><input type=\"checkbox\" name=\"regex\" value=\"1\"$checked>$I[regex]</label></td>";
1332 echo "<td style=\"width:5em;\"><label><input type=\"checkbox\" name=\"kick\" value=\"1\"$checkedk>$I[kick]</label></td>";
1333 echo "<td style=\"width:5em;\"><label><input type=\"checkbox\" name=\"cs\" value=\"1\"$checkedcs>$I[cs]</label></td>";
1334 echo '<td class="filtersubmit" style="width:5em;">'.submit($I['change']).'</td></tr></table></form></td></tr>';
1335 }
1336 echo '<tr><td>';
1337 echo form('admin', 'filter').hidden('id', '+');
1338 echo "<table style=\"width:100%;\"><tr><th style=\"width:8em\">$I[newfilter]</th>";
1339 echo "<td style=\"width:12em;\"><input type=\"text\" name=\"match\" value=\"\" size=\"20\" style=\"$U[style]\"></td>";
1340 echo "<td style=\"width:12em;\"><input type=\"text\" name=\"replace\" value=\"\" size=\"20\" style=\"$U[style]\"></td>";
1341 echo "<td style=\"width:9em;\"><label><input type=\"checkbox\" name=\"allowinpm\" id=\"allowinpm\" value=\"1\">$I[allowpm]</label></td>";
1342 echo "<td style=\"width:5em;\"><label><input type=\"checkbox\" name=\"regex\" id=\"regex\" value=\"1\">$I[regex]</label></td>";
1343 echo "<td style=\"width:5em;\"><label><input type=\"checkbox\" name=\"kick\" id=\"kick\" value=\"1\">$I[kick]</label></td>";
1344 echo "<td style=\"width:5em;\"><label><input type=\"checkbox\" name=\"cs\" id=\"cs\" value=\"1\">$I[cs]</label></td>";
1345 echo '<td class="filtersubmit" style="width:5em;">'.submit($I['add']).'</td></tr></table></form></td></tr>';
1346 echo "</table><br>";
1347 echo form('admin', 'filter').submit($I['reload']).'</form>';
1348 print_end();
1349}
1350
1351function send_linkfilter($arg=''){
1352 global $I, $U;
1353 print_start('linkfilter');
1354 echo "<h2>$I[linkfilter]</h2><i>$arg</i><table>";
1355 thr();
1356 echo '<tr><th><table style="width:100%;"><tr>';
1357 echo "<td style=\"width:8em;\">$I[fid]</td>";
1358 echo "<td style=\"width:12em;\">$I[match]</td>";
1359 echo "<td style=\"width:12em;\">$I[replace]</td>";
1360 echo "<td style=\"width:5em;\">$I[regex]</td>";
1361 echo "<td style=\"width:5em;\">$I[apply]</td>";
1362 echo '</tr></table></th></tr>';
1363 $filters=get_linkfilters();
1364 foreach($filters as $filter){
1365 if($filter['regex']==1){
1366 $checked=' checked';
1367 }else{
1368 $checked='';
1369 $filter['match']=preg_replace('/(\\\\(.))/u', "$2", $filter['match']);
1370 }
1371 echo '<tr><td>';
1372 echo form('admin', 'linkfilter').hidden('id', $filter['id']);
1373 echo "<table style=\"width:100%;\"><tr><th style=\"width:8em;\">$I[filter] $filter[id]:</th>";
1374 echo "<td style=\"width:12em;\"><input type=\"text\" name=\"match\" value=\"$filter[match]\" size=\"20\" style=\"$U[style]\"></td>";
1375 echo '<td style="width:12em;"><input type="text" name="replace" value="'.htmlspecialchars($filter['replace'])."\" size=\"20\" style=\"$U[style]\"></td>";
1376 echo "<td style=\"width:5em;\"><label><input type=\"checkbox\" name=\"regex\" value=\"1\"$checked>$I[regex]</label></td>";
1377 echo '<td class="filtersubmit" style="width:5em;">'.submit($I['change']).'</td></tr></table></form></td></tr>';
1378 }
1379 echo '<tr><td>';
1380 echo form('admin', 'linkfilter').hidden('id', '+');
1381 echo "<table style=\"width:100%;\"><tr><th style=\"width:8em;\">$I[newfilter]</th>";
1382 echo "<td style=\"width:12em;\"><input type=\"text\" name=\"match\" value=\"\" size=\"20\" style=\"$U[style]\"></td>";
1383 echo "<td style=\"width:12em;\"><input type=\"text\" name=\"replace\" value=\"\" size=\"20\" style=\"$U[style]\"></td>";
1384 echo "<td style=\"width:5em;\"><label><input type=\"checkbox\" name=\"regex\" value=\"1\">$I[regex]</label></td>";
1385 echo '<td class="filtersubmit" style="width:5em;">'.submit($I['add']).'</td></tr></table></form></td></tr>';
1386 echo "</table><br>";
1387 echo form('admin', 'linkfilter').submit($I['reload']).'</form>';
1388 print_end();
1389}
1390
1391function send_frameset(){
1392 global $I, $U, $db, $language;
1393 echo '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd"><html><head>'.meta_html();
1394 echo '<title>'.get_setting('chatname').'</title>';
1395 print_stylesheet();
1396 echo '</head>';
1397 if(isset($_REQUEST['sort'])){
1398 if($_REQUEST['sort']==1){
1399 $U['sortupdown']=1;
1400 $tmp=$U['nocache'];
1401 $U['nocache']=$U['nocache_old'];
1402 $U['nocache_old']=$tmp;
1403 }else{
1404 $U['sortupdown']=0;
1405 $tmp=$U['nocache'];
1406 $U['nocache']=$U['nocache_old'];
1407 $U['nocache_old']=$tmp;
1408 }
1409 $stmt=$db->prepare('UPDATE ' . PREFIX . 'sessions SET sortupdown=?, nocache=?, nocache_old=? WHERE nickname=?;');
1410 $stmt->execute([$U['sortupdown'], $U['nocache'], $U['nocache_old'], $U['nickname']]);
1411 if($U['status']>1){
1412 $stmt=$db->prepare('UPDATE ' . PREFIX . 'members SET sortupdown=?, nocache=?, nocache_old=? WHERE nickname=?;');
1413 $stmt->execute([$U['sortupdown'], $U['nocache'], $U['nocache_old'], $U['nickname']]);
1414 }
1415 }
1416 if($U['sortupdown']){
1417 $bottom='#bottom';
1418 }else{
1419 $bottom='';
1420 }
1421 if(($U['status']>=5 || ($U['status']>2 && get_count_mods()==0)) && get_setting('enfileupload')){
1422 $postheight=120;
1423 }else{
1424 $postheight=100;
1425 }
1426 if((!isset($_REQUEST['sort']) && !$U['sortupdown']) || (isset($_REQUEST['sort']) && $_REQUEST['sort']==0)){
1427 echo "<frameset rows=\"$postheight,*,45\" border=\"3\" frameborder=\"3\" framespacing=\"3\">";
1428 echo "<frame name=\"post\" src=\"$_SERVER[SCRIPT_NAME]?action=post&session=$U[session]&lang=$language\">";
1429 if(get_setting('enablegreeting')){
1430 echo "<frame name=\"view\" src=\"$_SERVER[SCRIPT_NAME]?action=greeting&session=$U[session]&lang=$language\">";
1431 }else{
1432 echo "<frame name=\"view\" src=\"$_SERVER[SCRIPT_NAME]?action=view&session=$U[session]&lang=$language$bottom\">";
1433 }
1434 echo "<frame name=\"controls\" src=\"$_SERVER[SCRIPT_NAME]?action=controls&session=$U[session]&lang=$language&sort=1\">";
1435 }else{
1436 echo "<frameset rows=\"45,*,$postheight\" border=\"3\" frameborder=\"3\" framespacing=\"3\">";
1437 echo "<frame name=\"controls\" src=\"$_SERVER[SCRIPT_NAME]?action=controls&session=$U[session]&lang=$language&sort=0\">";
1438 if(get_setting('enablegreeting')){
1439 echo "<frame name=\"view\" src=\"$_SERVER[SCRIPT_NAME]?action=greeting&session=$U[session]&lang=$language\">";
1440 }else{
1441 echo "<frame name=\"view\" src=\"$_SERVER[SCRIPT_NAME]?action=view&session=$U[session]&lang=$language$bottom\">";
1442 }
1443 echo "<frame name=\"post\" src=\"$_SERVER[SCRIPT_NAME]?action=post&session=$U[session]&lang=$language\">";
1444 }
1445 echo "<noframes><body>$I[noframes]".form_target('_parent', '').submit($I['backtologin'], 'class="backbutton"').'</form></body></noframes></frameset></html>';
1446 exit;
1447}
1448
1449function send_messages(){
1450 global $I, $U, $language;
1451 if($U['nocache']){
1452 $nocache='&nc='.substr(time(), -6);
1453 }else{
1454 $nocache='';
1455 }
1456 if($U['sortupdown']){
1457 $sort='#bottom';
1458 }else{
1459 $sort='';
1460 }
1461 print_start('messages', $U['refresh'], "$_SERVER[SCRIPT_NAME]?action=view&session=$U[session]&lang=$language$nocache$sort");
1462 echo '<a id="top"></a>';
1463 echo "<a id=\"bottom_link\" href=\"#bottom\">$I[bottom]</a>";
1464 echo "<div id=\"manualrefresh\"><br>$I[manualrefresh]<br>".form('view').submit($I['reload']).'</form><br></div>';
1465 if(!$U['sortupdown']){
1466 echo '<div id="topic">';
1467 echo get_setting('topic');
1468 echo '</div>';
1469 print_chatters();
1470 print_notifications();
1471 print_messages();
1472 }else{
1473 print_messages();
1474 print_notifications();
1475 print_chatters();
1476 echo '<div id="topic">';
1477 echo get_setting('topic');
1478 echo '</div>';
1479 }
1480 echo "<a id=\"bottom\"></a><a id=\"top_link\" href=\"#top\">$I[top]</a>";
1481 print_end();
1482}
1483
1484function send_inbox(){
1485 global $I, $U, $db;
1486 print_start('inbox');
1487 echo form('inbox', 'clean').submit($I['delselmes'], 'class="delbutton"').'<br><br>';
1488 $dateformat=get_setting('dateformat');
1489 if(!$U['embed'] && get_setting('imgembed')){
1490 $removeEmbed=true;
1491 }else{
1492 $removeEmbed=false;
1493 }
1494 if($U['timestamps'] && !empty($dateformat)){
1495 $timestamps=true;
1496 }else{
1497 $timestamps=false;
1498 }
1499 if($U['sortupdown']){
1500 $direction='ASC';
1501 }else{
1502 $direction='DESC';
1503 }
1504 $stmt=$db->prepare('SELECT id, postdate, text FROM ' . PREFIX . "inbox WHERE recipient=? ORDER BY id $direction;");
1505 $stmt->execute([$U['nickname']]);
1506 while($message=$stmt->fetch(PDO::FETCH_ASSOC)){
1507 prepare_message_print($message, $removeEmbed);
1508 echo "<div class=\"msg\"><label><input type=\"checkbox\" name=\"mid[]\" value=\"$message[id]\">";
1509 if($timestamps){
1510 echo ' <small>'.date($dateformat, $message['postdate']).' - </small>';
1511 }
1512 echo " $message[text]</label></div>";
1513 }
1514 echo '</form><br>'.form('view').submit($I['backtochat'], 'class="backbutton"').'</form>';
1515 print_end();
1516}
1517
1518function send_notes($type){
1519 global $I, $U, $db;
1520 print_start('notes');
1521 $personalnotes=(bool) get_setting('personalnotes');
1522 if($U['status']>=5 && ($personalnotes || $U['status']>6)){
1523 echo '<table><tr>';
1524 if($U['status']>6){
1525 echo '<td>'.form_target('view', 'notes', 'admin').submit($I['admnotes']).'</form></td>';
1526 }
1527 echo '<td>'.form_target('view', 'notes', 'staff').submit($I['staffnotes']).'</form></td>';
1528 if($personalnotes){
1529 echo '<td>'.form_target('view', 'notes').submit($I['personalnotes']).'</form></td>';
1530 }
1531 echo '</tr></table>';
1532 }
1533 if($type===1){
1534 echo "<h2>$I[staffnotes]</h2><p>";
1535 $hiddendo=hidden('do', 'staff');
1536 }elseif($type===0){
1537 echo "<h2>$I[adminnotes]</h2><p>";
1538 $hiddendo=hidden('do', 'admin');
1539 }else{
1540 echo "<h2>$I[personalnotes]</h2><p>";
1541 $hiddendo='';
1542 }
1543 if(isset($_REQUEST['text'])){
1544 if(MSGENCRYPTED){
1545 $_REQUEST['text']=openssl_encrypt($_REQUEST['text'], 'aes-256-cbc', ENCRYPTKEY, 0, '1234567890123456');
1546 }
1547 $time=time();
1548 $stmt=$db->prepare('INSERT INTO ' . PREFIX . 'notes (type, lastedited, editedby, text) VALUES (?, ?, ?, ?);');
1549 $stmt->execute([$type, $time, $U['nickname'], $_REQUEST['text']]);
1550 echo "<b>$I[notessaved]</b> ";
1551 }
1552 $dateformat=get_setting('dateformat');
1553 if($type!==2){
1554 $stmt=$db->prepare('SELECT COUNT(*) FROM ' . PREFIX . 'notes WHERE type=?;');
1555 $stmt->execute([$type]);
1556 }else{
1557 $stmt=$db->prepare('SELECT COUNT(*) FROM ' . PREFIX . 'notes WHERE type=? AND editedby=?;');
1558 $stmt->execute([$type, $U['nickname']]);
1559 }
1560 $num=$stmt->fetch(PDO::FETCH_NUM);
1561 if(!empty($_REQUEST['revision'])){
1562 $revision=intval($_REQUEST['revision']);
1563 }else{
1564 $revision=0;
1565 }
1566 if($type!==2){
1567 $stmt=$db->prepare('SELECT * FROM ' . PREFIX . "notes WHERE type=? ORDER BY id DESC LIMIT 1 OFFSET $revision;");
1568 $stmt->execute([$type]);
1569 }else{
1570 $stmt=$db->prepare('SELECT * FROM ' . PREFIX . "notes WHERE type=? AND editedby=? ORDER BY id DESC LIMIT 1 OFFSET $revision;");
1571 $stmt->execute([$type, $U['nickname']]);
1572 }
1573 if($note=$stmt->fetch(PDO::FETCH_ASSOC)){
1574 printf($I['lastedited'], htmlspecialchars($note['editedby']), date($dateformat, $note['lastedited']));
1575 }else{
1576 $note['text']='';
1577 }
1578 if(MSGENCRYPTED){
1579 $note['text']=openssl_decrypt($note['text'], 'aes-256-cbc', ENCRYPTKEY, 0, '1234567890123456');
1580 }
1581 echo "</p>".form('notes');
1582 echo "$hiddendo<textarea name=\"text\">".htmlspecialchars($note['text']).'</textarea><br>';
1583 echo submit($I['savenotes']).'</form><br>';
1584 if($num[0]>1){
1585 echo "<br><table><tr><td>$I[revisions]</td>";
1586 if($revision<$num[0]-1){
1587 echo '<td>'.form('notes').hidden('revision', $revision+1);
1588 echo $hiddendo.submit($I['older']).'</form></td>';
1589 }
1590 if($revision>0){
1591 echo '<td>'.form('notes').hidden('revision', $revision-1);
1592 echo $hiddendo.submit($I['newer']).'</form></td>';
1593 }
1594 echo '</tr></table>';
1595 }
1596 print_end();
1597}
1598
1599function send_approve_waiting(){
1600 global $I, $db;
1601 print_start('approve_waiting');
1602 echo "<h2>$I[waitingroom]</h2>";
1603 $result=$db->query('SELECT * FROM ' . PREFIX . 'sessions WHERE entry=0 AND status=1 ORDER BY id LIMIT 100;');
1604 if($tmp=$result->fetchAll(PDO::FETCH_ASSOC)){
1605 echo form('admin', 'approve');
1606 echo '<table>';
1607 echo "<tr><th>$I[sessnick]</th><th>$I[sessua]</th></tr>";
1608 foreach($tmp as $temp){
1609 echo '<tr>'.hidden('alls[]', htmlspecialchars($temp['nickname']));
1610 echo '<td><label><input type="checkbox" name="csid[]" value="'.htmlspecialchars($temp['nickname']).'">';
1611 echo style_this(htmlspecialchars($temp['nickname']), $temp['style']).'</label></td>';
1612 echo "<td>$temp[useragent]</td></tr>";
1613 }
1614 echo "</table><br><table id=\"action\"><tr><td><label><input type=\"radio\" name=\"what\" value=\"allowchecked\" id=\"allowchecked\" checked>$I[allowchecked]</label></td>";
1615 echo "<td><label><input type=\"radio\" name=\"what\" value=\"allowall\" id=\"allowall\">$I[allowall]</label></td>";
1616 echo "<td><label><input type=\"radio\" name=\"what\" value=\"denychecked\" id=\"denychecked\">$I[denychecked]</label></td>";
1617 echo "<td><label><input type=\"radio\" name=\"what\" value=\"denyall\" id=\"denyall\">$I[denyall]</label></td></tr><tr><td colspan=\"8\">$I[denymessage] <input type=\"text\" name=\"kickmessage\" size=\"45\"></td>";
1618 echo '</tr><tr><td colspan="8">'.submit($I['butallowdeny']).'</td></tr></table></form>';
1619 }else{
1620 echo "$I[waitempty]<br>";
1621 }
1622 echo '<br>'.form('view').submit($I['backtochat'], 'class="backbutton"').'</form>';
1623 print_end();
1624}
1625
1626function send_waiting_room(){
1627 global $I, $U, $db, $language;
1628 $ga=(int) get_setting('guestaccess');
1629 if($ga===3 && (get_count_mods()>0 || !get_setting('modfallback'))){
1630 $wait=false;
1631 }else{
1632 $wait=true;
1633 }
1634 check_expired();
1635 check_kicked();
1636 $timeleft=get_setting('entrywait')-(time()-$U['lastpost']);
1637 if($wait && ($timeleft<=0 || $ga===1)){
1638 $U['entry']=$U['lastpost'];
1639 $stmt=$db->prepare('UPDATE ' . PREFIX . 'sessions SET entry=lastpost WHERE session=?;');
1640 $stmt->execute([$U['session']]);
1641 send_frameset();
1642 }elseif(!$wait && $U['entry']!=0){
1643 send_frameset();
1644 }else{
1645 $refresh=(int) get_setting('defaultrefresh');
1646 print_start('waitingroom', $refresh, "$_SERVER[SCRIPT_NAME]?action=wait&session=$U[session]&lang=$language&nc=".substr(time(),-6));
1647 echo "<h2>$I[waitingroom]</h2><p>";
1648 if($wait){
1649 printf($I['waittext'], style_this(htmlspecialchars($U['nickname']), $U['style']), $timeleft);
1650 }else{
1651 printf($I['admwaittext'], style_this(htmlspecialchars($U['nickname']), $U['style']));
1652 }
1653 echo '</p><br><p>';
1654 printf($I['waitreload'], $refresh);
1655 echo '</p><br><br>';
1656 echo '<hr>'.form('wait');
1657 if(!isset($_REQUEST['session'])){
1658 echo hidden('session', $U['session']);
1659 }
1660 echo submit($I['reload']).'</form><br>';
1661 echo form('logout');
1662 if(!isset($_REQUEST['session'])){
1663 echo hidden('session', $U['session']);
1664 }
1665 echo submit($I['exit'], 'id="exitbutton"').'</form>';
1666 $rulestxt=get_setting('rulestxt');
1667 if(!empty($rulestxt)){
1668 echo "<div id=\"rules\"><h2>$I[rules]</h2><b>$rulestxt</b></div>";
1669 }
1670 print_end();
1671 }
1672}
1673
1674function send_choose_messages(){
1675 global $I, $U;
1676 print_start('choose_messages');
1677 echo form('admin', 'clean');
1678 echo hidden('what', 'selected').submit($I['delselmes'], 'class="delbutton"').'<br><br>';
1679 print_messages($U['status']);
1680 echo '<br>'.submit($I['delselmes'], 'class="delbutton"')."</form>";
1681 print_end();
1682}
1683
1684function send_del_confirm(){
1685 global $I;
1686 print_start('del_confirm');
1687 echo "<table><tr><td colspan=\"2\">$I[confirm]</td></tr><tr><td>".form('delete');
1688 if(isset($_REQUEST['multi'])){
1689 echo hidden('multi', 'on');
1690 }
1691 if(isset($_REQUEST['sendto'])){
1692 echo hidden('sendto', $_REQUEST['sendto']);
1693 }
1694 echo hidden('confirm', 'yes').hidden('what', $_REQUEST['what']).submit($I['yes'], 'class="delbutton"').'</form></td><td>'.form('post');
1695 if(isset($_REQUEST['multi'])){
1696 echo hidden('multi', 'on');
1697 }
1698 if(isset($_REQUEST['sendto'])){
1699 echo hidden('sendto', $_REQUEST['sendto']);
1700 }
1701 echo submit($I['no'], 'class="backbutton"').'</form></td><tr></table>';
1702 print_end();
1703}
1704
1705function send_post($rejected=''){
1706 global $I, $U, $db;
1707 print_start('post');
1708 if(!isset($_REQUEST['sendto'])){
1709 $_REQUEST['sendto']='';
1710 }
1711 echo '<table><tr><td>'.form('post');
1712 echo hidden('postid', substr(time(), -6));
1713 if(isset($_REQUEST['multi'])){
1714 echo hidden('multi', 'on');
1715 }
1716 echo '<table><tr><td><table><tr id="firstline"><td>'.style_this(htmlspecialchars($U['nickname']), $U['style']).'</td><td>:</td>';
1717 if(isset($_REQUEST['multi'])){
1718 echo "<td><textarea name=\"message\" rows=\"3\" cols=\"40\" style=\"$U[style]\" autofocus>$rejected</textarea></td>";
1719 }else{
1720 echo "<td><input type=\"text\" name=\"message\" value=\"$rejected\" size=\"40\" style=\"$U[style]\" autofocus></td>";
1721 }
1722 echo '<td>'.submit($I['talkto']).'</td><td><select name="sendto" size="1">';
1723 echo '<option ';
1724 if($_REQUEST['sendto']==='s *'){
1725 echo 'selected ';
1726 }
1727 echo "value=\"s *\">-$I[toall]-</option>";
1728 if($U['status']>=3){
1729 echo '<option ';
1730 if($_REQUEST['sendto']==='s ?'){
1731 echo 'selected ';
1732 }
1733 echo "value=\"s ?\">-$I[tomem]-</option>";
1734 }
1735 if($U['status']>=5){
1736 echo '<option ';
1737 if($_REQUEST['sendto']==='s #'){
1738 echo 'selected ';
1739 }
1740 echo "value=\"s #\">-$I[tostaff]-</option>";
1741 }
1742 if($U['status']>=6){
1743 echo '<option ';
1744 if($_REQUEST['sendto']==='s &'){
1745 echo 'selected ';
1746 }
1747 echo "value=\"s &\">-$I[toadmin]-</option>";
1748 }
1749 $disablepm=(bool) get_setting('disablepm');
1750 if(!$disablepm){
1751 $users=[];
1752 $stmt=$db->prepare('SELECT * FROM (SELECT nickname, style, 0 AS offline FROM ' . PREFIX . 'sessions WHERE entry!=0 AND status>0 AND incognito=0 UNION SELECT nickname, style, 1 AS offline FROM ' . PREFIX . 'members WHERE eninbox!=0 AND eninbox<=? AND nickname NOT IN (SELECT nickname FROM ' . PREFIX . 'sessions WHERE incognito=0)) AS t WHERE nickname NOT IN (SELECT ign FROM '. PREFIX . 'ignored WHERE ignby=? UNION SELECT ignby FROM '. PREFIX . 'ignored WHERE ign=?) ORDER BY LOWER(nickname);');
1753 $stmt->execute([$U['status'], $U['nickname'], $U['nickname']]);
1754 while($tmp=$stmt->fetch(PDO::FETCH_ASSOC)){
1755 if($tmp['offline']){
1756 $users[]=["$tmp[nickname] $I[offline]", $tmp['style'], $tmp['nickname']];
1757 }else{
1758 $users[]=[$tmp['nickname'], $tmp['style'], $tmp['nickname']];
1759 }
1760 }
1761 foreach($users as $user){
1762 if($U['nickname']!==$user[2]){
1763 echo '<option ';
1764 if($_REQUEST['sendto']==$user[2]){
1765 echo 'selected ';
1766 }
1767 echo 'value="'.htmlspecialchars($user[2])."\" style=\"$user[1]\">".htmlspecialchars($user[0]).'</option>';
1768 }
1769 }
1770 }
1771 echo '</select></td>';
1772 if(get_setting('enfileupload')){
1773 if(!$disablepm && ($U['status']>=5 || ($U['status']>=3 && get_count_mods()==0 && get_setting('memkick')))){
1774 echo '</tr></table><table><tr id="secondline">';
1775 }
1776 printf("<td><input type=\"file\" name=\"file\"><small>$I[maxsize]</small></td>", get_setting('maxuploadsize'));
1777 }
1778 if(!$disablepm && ($U['status']>=5 || ($U['status']>=3 && get_count_mods()==0 && get_setting('memkick')))){
1779 echo "<td><label><input type=\"checkbox\" name=\"kick\" id=\"kick\" value=\"kick\">$I[kick]</label></td>";
1780 echo "<td><label><input type=\"checkbox\" name=\"what\" id=\"what\" value=\"purge\" checked>$I[alsopurge]</label></td>";
1781 }
1782 echo '</tr></table></td></tr></table></form></td></tr><tr><td><table><tr id="thirdline"><td>'.form('delete');
1783 if(isset($_REQUEST['multi'])){
1784 echo hidden('multi', 'on');
1785 }
1786 echo hidden('sendto', $_REQUEST['sendto']).hidden('what', 'last');
1787 echo submit($I['dellast'], 'class="delbutton"').'</form></td><td>'.form('delete');
1788 if(isset($_REQUEST['multi'])){
1789 echo hidden('multi', 'on');
1790 }
1791 echo hidden('sendto', $_REQUEST['sendto']).hidden('what', 'all');
1792 echo submit($I['delall'], 'class="delbutton"').'</form></td><td style="width:10px;"></td><td>'.form('post');
1793 if(isset($_REQUEST['multi'])){
1794 echo submit($I['switchsingle']);
1795 }else{
1796 echo hidden('multi', 'on').submit($I['switchmulti']);
1797 }
1798 echo hidden('sendto', $_REQUEST['sendto']).'</form></td>';
1799 echo '</tr></table></td></tr></table>';
1800 print_end();
1801}
1802
1803function send_greeting(){
1804 global $I, $U, $language;
1805 print_start('greeting', $U['refresh'], "$_SERVER[SCRIPT_NAME]?action=view&session=$U[session]&lang=$language");
1806 printf("<h1>$I[greetingmsg]</h1>", style_this(htmlspecialchars($U['nickname']), $U['style']));
1807 printf("<hr><small>$I[entryhelp]</small>", $U['refresh']);
1808 $rulestxt=get_setting('rulestxt');
1809 if(!empty($rulestxt)){
1810 echo "<hr><div id=\"rules\"><h2>$I[rules]</h2>$rulestxt</div>";
1811 }
1812 print_end();
1813}
1814
1815function send_help(){
1816 global $I, $U;
1817 print_start('help');
1818 $rulestxt=get_setting('rulestxt');
1819 if(!empty($rulestxt)){
1820 echo "<div id=\"rules\"><h2>$I[rules]</h2>$rulestxt<br></div><hr>";
1821 }
1822 echo "<h2>$I[help]</h2>$I[helpguest]";
1823 if(get_setting('imgembed')){
1824 echo "<br>$I[helpembed]";
1825 }
1826 if($U['status']>=3){
1827 echo "<br>$I[helpmem]<br>";
1828 if($U['status']>=5){
1829 echo "<br>$I[helpmod]<br>";
1830 if($U['status']>=7){
1831 echo "<br>$I[helpadm]<br>";
1832 }
1833 }
1834 }
1835 echo '<br><hr><div id="backcredit">'.form('view').submit($I['backtochat'], 'class="backbutton"').'</form>'.credit().'</div>';
1836 print_end();
1837}
1838
1839function send_profile($arg=''){
1840 global $I, $L, $U, $db, $language;
1841 print_start('profile');
1842 echo form('profile', 'save')."<h2>$I[profile]</h2><i>$arg</i><table>";
1843 thr();
1844 $ignored=[];
1845 $stmt=$db->prepare('SELECT ign FROM ' . PREFIX . 'ignored WHERE ignby=? ORDER BY LOWER(ign);');
1846 $stmt->execute([$U['nickname']]);
1847 while($tmp=$stmt->fetch(PDO::FETCH_ASSOC)){
1848 $ignored[]=htmlspecialchars($tmp['ign']);
1849 }
1850 if(count($ignored)>0){
1851 echo "<tr><td><table id=\"unignore\"><tr><th>$I[unignore]</th><td>";
1852 echo "<select name=\"unignore\" size=\"1\"><option value=\"\">$I[choose]</option>";
1853 foreach($ignored as $ign){
1854 echo "<option value=\"$ign\">$ign</option>";
1855 }
1856 echo '</select></td></tr></table></td></tr>';
1857 thr();
1858 }
1859 echo "<tr><td><table id=\"ignore\"><tr><th>$I[ignore]</th><td>";
1860 echo "<select name=\"ignore\" size=\"1\"><option value=\"\">$I[choose]</option>";
1861 $stmt=$db->prepare('SELECT poster, style FROM ' . PREFIX . 'messages INNER JOIN (SELECT nickname, style FROM ' . PREFIX . 'sessions UNION SELECT nickname, style FROM ' . PREFIX . 'members) AS t ON (' . PREFIX . 'messages.poster=t.nickname) WHERE poster!=? AND poster NOT IN (SELECT ign FROM ' . PREFIX . 'ignored WHERE ignby=?) GROUP BY poster ORDER BY LOWER(poster);');
1862 $stmt->execute([$U['nickname'], $U['nickname']]);
1863 while($nick=$stmt->fetch(PDO::FETCH_NUM)){
1864 echo '<option value="'.htmlspecialchars($nick[0])."\" style=\"$nick[1]\">".htmlspecialchars($nick[0]).'</option>';
1865 }
1866 echo '</select></td></tr></table></td></tr>';
1867 thr();
1868 echo "<tr><td><table id=\"refresh\"><tr><th>$I[refreshrate]</th><td>";
1869 echo "<input type=\"number\" name=\"refresh\" size=\"3\" maxlength=\"3\" min=\"5\" max=\"150\" value=\"$U[refresh]\"></td></tr></table></td></tr>";
1870 thr();
1871 preg_match('/#([0-9a-f]{6})/i', $U['style'], $matches);
1872 echo "<tr><td><table id=\"colour\"><tr><th>$I[fontcolour] (<a href=\"$_SERVER[SCRIPT_NAME]?action=colours&session=$U[session]&lang=$language\" target=\"view\">$I[viewexample]</a>)</th><td>";
1873 echo "<input type=\"color\" value=\"#$matches[1]\" name=\"colour\"></td></tr></table></td></tr>";
1874 thr();
1875 echo "<tr><td><table id=\"bgcolour\"><tr><th>$I[bgcolour] (<a href=\"$_SERVER[SCRIPT_NAME]?action=colours&session=$U[session]&lang=$language\" target=\"view\">$I[viewexample]</a>)</th><td>";
1876 echo "<input type=\"color\" value=\"#$U[bgcolour]\" name=\"bgcolour\"></td></tr></table></td></tr>";
1877 thr();
1878 if($U['status']>=3){
1879 echo "<tr><td><table id=\"font\"><tr><th>$I[fontface]</th><td><table>";
1880 echo "<tr><td> </td><td><select name=\"font\" size=\"1\"><option value=\"\">* $I[roomdefault] *</option>";
1881 $F=load_fonts();
1882 foreach($F as $name=>$font){
1883 echo "<option style=\"$font\" ";
1884 if(strpos($U['style'], $font)!==false){
1885 echo 'selected ';
1886 }
1887 echo "value=\"$name\">$name</option>";
1888 }
1889 echo '</select></td><td> </td><td><label><input type="checkbox" name="bold" id="bold" value="on"';
1890 if(strpos($U['style'], 'font-weight:bold;')!==false){
1891 echo ' checked';
1892 }
1893 echo "><b>$I[bold]</b></label></td><td> </td><td><label><input type=\"checkbox\" name=\"italic\" id=\"italic\" value=\"on\"";
1894 if(strpos($U['style'], 'font-style:italic;')!==false){
1895 echo ' checked';
1896 }
1897 echo "><i>$I[italic]</i></label></td><td> </td><td><label><input type=\"checkbox\" name=\"small\" id=\"small\" value=\"on\"";
1898 if(strpos($U['style'], 'font-size:smaller;')!==false){
1899 echo ' checked';
1900 }
1901 echo "><small>$I[small]</small></label></td></tr></table></td></tr></table></td></tr>";
1902 thr();
1903 }
1904 echo '<tr><td>'.style_this(htmlspecialchars($U['nickname'])." : $I[fontexample]", $U['style']).'</td></tr>';
1905 thr();
1906 $bool_settings=['timestamps', 'nocache', 'sortupdown', 'hidechatters'];
1907 if(get_setting('imgembed')){
1908 $bool_settings[]='embed';
1909 }
1910 if($U['status']>=5 && get_setting('incognito')){
1911 $bool_settings[]='incognito';
1912 }
1913 foreach($bool_settings as $setting){
1914 echo "<tr><td><table id=\"$setting\"><tr><th>".$I[$setting].'</th><td>';
1915 echo "<label><input type=\"checkbox\" name=\"$setting\" value=\"on\"";
1916 if($U[$setting]){
1917 echo ' checked';
1918 }
1919 echo "><b>$I[enabled]</b></label></td></tr></table></td></tr>";
1920 thr();
1921 }
1922 if($U['status']>=2 && get_setting('eninbox')){
1923 echo "<tr><td><table id=\"eninbox\"><tr><th>$I[eninbox]</th><td>";
1924 echo "<select name=\"eninbox\" id=\"eninbox\">";
1925 echo '<option value="0"';
1926 if($U['eninbox']==0){
1927 echo ' selected';
1928 }
1929 echo ">$I[disabled]</option>";
1930 echo '<option value="1"';
1931 if($U['eninbox']==1){
1932 echo ' selected';
1933 }
1934 echo ">$I[eninall]</option>";
1935 echo '<option value="3"';
1936 if($U['eninbox']==3){
1937 echo ' selected';
1938 }
1939 echo ">$I[eninmem]</option>";
1940 echo '<option value="5"';
1941 if($U['eninbox']==5){
1942 echo ' selected';
1943 }
1944 echo ">$I[eninstaff]</option>";
1945 echo '</select></td></tr></table></td></tr>';
1946 thr();
1947 }
1948 echo "<tr><td><table id=\"tz\"><tr><th>$I[tz]</th><td>";
1949 echo "<select name=\"tz\">";
1950 $tzs=timezone_identifiers_list();
1951 foreach($tzs as $tz){
1952 echo "<option value=\"$tz\"";
1953 if($U['tz']==$tz){
1954 echo ' selected';
1955 }
1956 echo ">$tz</option>";
1957 }
1958 echo '</select></td></tr></table></td></tr>';
1959 thr();
1960 if($U['status']>=2){
1961 echo "<tr><td><table id=\"changepass\"><tr><th>$I[changepass]</th></tr>";
1962 echo '<tr><td><table>';
1963 echo "<tr><td> </td><td>$I[oldpass]</td><td><input type=\"password\" name=\"oldpass\" size=\"20\"></td></tr>";
1964 echo "<tr><td> </td><td>$I[newpass]</td><td><input type=\"password\" name=\"newpass\" size=\"20\"></td></tr>";
1965 echo "<tr><td> </td><td>$I[confirmpass]</td><td><input type=\"password\" name=\"confirmpass\" size=\"20\"></td></tr>";
1966 echo '</table></td></tr></table></td></tr>';
1967 thr();
1968 echo "<tr><td><table id=\"changenick\"><tr><th>$I[changenick]</th><td><table>";
1969 echo "<tr><td> </td><td>$I[newnickname]</td><td><input type=\"text\" name=\"newnickname\" size=\"20\">";
1970 echo '</table></td></tr></table></td></tr>';
1971 thr();
1972 }
1973 echo '<tr><td>'.submit($I['savechanges']).'</td></tr></table></form>';
1974 if($U['status']>1 && $U['status']<8){
1975 echo '<br>'.form('profile', 'delete').submit($I['deleteacc'], 'class="delbutton"').'</form>';
1976 }
1977 echo "<br><p id=\"changelang\">$I[changelang]";
1978 foreach($L as $lang=>$name){
1979 echo " <a href=\"$_SERVER[SCRIPT_NAME]?lang=$lang&session=$U[session]&action=controls\" target=\"controls\">$name</a>";
1980 }
1981 echo '</p><br>'.form('view').submit($I['backtochat'], 'class="backbutton"').'</form>';
1982 print_end();
1983}
1984
1985function send_controls(){
1986 global $I, $U;
1987 print_start('controls');
1988 $personalnotes=(bool) get_setting('personalnotes');
1989 echo '<table><tr>';
1990 echo '<td>'.form_target('post', 'post').submit($I['reloadpb']).'</form></td>';
1991 echo '<td>'.form_target('view', 'view').submit($I['reloadmsgs']).'</form></td>';
1992 echo '<td>'.form_target('view', 'profile').submit($I['chgprofile']).'</form></td>';
1993 if($U['status']>=5){
1994 echo '<td>'.form_target('view', 'admin').submit($I['adminbtn']).'</form></td>';
1995 if(!$personalnotes){
1996 echo '<td>'.form_target('view', 'notes', 'staff').submit($I['notes']).'</form></td>';
1997 }
1998 }
1999 if($U['status']>=3){
2000 if($personalnotes){
2001 echo '<td>'.form_target('view', 'notes').submit($I['notes']).'</form></td>';
2002 }
2003 echo '<td>'.form_target('_blank', 'login').submit($I['clone']).'</form></td>';
2004 }
2005 if(!isset($_REQUEST['sort'])){
2006 $sort=0;
2007 }else{
2008 $sort=$_REQUEST['sort'];
2009 }
2010 echo '<td>'.form_target('_parent', 'login').hidden('sort', $sort).submit($I['sortframe']).'</form></td>';
2011 echo '<td>'.form_target('view', 'help').submit($I['randh']).'</form></td>';
2012 echo '<td>'.form_target('_parent', 'logout').submit($I['exit'], 'id="exitbutton"').'</form></td>';
2013 echo '</tr></table>';
2014 print_end();
2015}
2016
2017function send_download(){
2018 global $I, $db;
2019 if(isset($_REQUEST['id'])){
2020 $stmt=$db->prepare('SELECT filename, type, data FROM ' . PREFIX . 'files WHERE hash=?;');
2021 $stmt->execute([$_REQUEST['id']]);
2022 if($data=$stmt->fetch(PDO::FETCH_ASSOC)){
2023 header("Content-Type: $data[type]");
2024 header("Content-Disposition: filename=\"$data[filename]\"");
2025 header('Pragma: no-cache');
2026 header('Cache-Control: no-cache, no-store, must-revalidate, max-age=0, private');
2027 header('Expires: 0');
2028 echo base64_decode($data['data']);
2029 }else{
2030 send_error($I['filenotfound']);
2031 }
2032 }else{
2033 send_error($I['filenotfound']);
2034 }
2035}
2036
2037function send_logout(){
2038 global $I, $U;
2039 print_start('logout');
2040 echo '<h1>'.sprintf($I['bye'], style_this(htmlspecialchars($U['nickname']), $U['style'])).'</h1>'.form_target('_parent', '').submit($I['backtologin'], 'class="backbutton"').'</form>';
2041 print_end();
2042}
2043
2044function send_colours(){
2045 global $I;
2046 print_start('colours');
2047 echo "<h2>$I[colourtable]</h2><kbd><b>";
2048 for($red=0x00;$red<=0xFF;$red+=0x33){
2049 for($green=0x00;$green<=0xFF;$green+=0x33){
2050 for($blue=0x00;$blue<=0xFF;$blue+=0x33){
2051 $hcol=sprintf('%02X%02X%02X', $red, $green, $blue);
2052 echo "<span style=\"color:#$hcol\">$hcol</span> ";
2053 }
2054 echo '<br>';
2055 }
2056 echo '<br>';
2057 }
2058 echo '</b></kbd>'.form('profile').submit($I['backtoprofile'], ' class="backbutton"').'</form>';
2059 print_end();
2060}
2061
2062function send_login(){
2063 global $I, $L;
2064 $ga=(int) get_setting('guestaccess');
2065 if($ga===4){
2066 send_chat_disabled();
2067 }
2068 print_start('login');
2069 $englobal=(int) get_setting('englobalpass');
2070 echo '<h1 id="chatname">'.get_setting('chatname').'</h1>';
2071 echo form_target('_parent', 'login');
2072 if($englobal===1 && isset($_REQUEST['globalpass'])){
2073 echo hidden('globalpass', $_REQUEST['globalpass']);
2074 }
2075 echo '<table>';
2076 if($englobal!==1 || (isset($_REQUEST['globalpass']) && $_REQUEST['globalpass']==get_setting('globalpass'))){
2077 echo "<tr><td>$I[nick]</td><td><input type=\"text\" name=\"nick\" size=\"15\" autofocus></td></tr>";
2078 echo "<tr><td>$I[pass]</td><td><input type=\"password\" name=\"pass\" size=\"15\"></td></tr>";
2079 send_captcha();
2080 if($ga!==0){
2081 if(get_setting('guestreg')!=0){
2082 echo "<tr><td>$I[regpass]</td><td><input type=\"password\" name=\"regpass\" size=\"15\" placeholder=\"$I[optional]\"></td></tr>";
2083 }
2084 if($englobal===2){
2085 echo "<tr><td>$I[globalloginpass]</td><td><input type=\"password\" name=\"globalpass\" size=\"15\"></td></tr>";
2086 }
2087 echo "<tr><td colspan=\"2\">$I[choosecol]<br><select name=\"colour\"><option value=\"\">* $I[randomcol] *</option>";
2088 print_colours();
2089 echo '</select></td></tr>';
2090 }else{
2091 echo "<tr><td colspan=\"2\">$I[noguests]</td></tr>";
2092 }
2093 echo '<tr><td colspan="2">'.submit($I['enter']).'</td></tr></table></form>';
2094 get_nowchatting();
2095 echo '<br><div id="topic">';
2096 echo get_setting('topic');
2097 echo '</div>';
2098 $rulestxt=get_setting('rulestxt');
2099 if(!empty($rulestxt)){
2100 echo "<div id=\"rules\"><h2>$I[rules]</h2><b>$rulestxt</b></div>";
2101 }
2102 }else{
2103 echo "<tr><td>$I[globalloginpass]</td><td><input type=\"password\" name=\"globalpass\" size=\"15\" autofocus></td></tr>";
2104 if($ga===0){
2105 echo "<tr><td colspan=\"2\">$I[noguests]</td></tr>";
2106 }
2107 echo '<tr><td colspan="2">'.submit($I['enter']).'</td></tr></table></form>';
2108 }
2109 echo "<p id=\"changelang\">$I[changelang]";
2110 foreach($L as $lang=>$name){
2111 echo " <a href=\"$_SERVER[SCRIPT_NAME]?lang=$lang\">$name</a>";
2112 }
2113 echo '</p>'.credit();
2114 print_end();
2115}
2116
2117function send_chat_disabled(){
2118 print_start('disabled');
2119 echo get_setting('disabletext');
2120 print_end();
2121}
2122
2123function send_error($err){
2124 global $I;
2125 print_start('error');
2126 echo "<h2>$I[error]: $err</h2>".form_target('_parent', '').submit($I['backtologin'], 'class="backbutton"').'</form>';
2127 print_end();
2128}
2129
2130function send_fatal_error($err){
2131 global $I;
2132 echo '<!DOCTYPE html><html><head>'.meta_html();
2133 echo "<title>$I[fatalerror]</title>";
2134 echo "<style type=\"text/css\">body{background-color:#000000;color:#FF0033;}</style>";
2135 echo '</head><body>';
2136 echo "<h2>$I[fatalerror]: $err</h2>";
2137 print_end();
2138}
2139
2140function print_notifications(){
2141 global $I, $U, $db;
2142 echo '<span id="notifications">';
2143 if($U['status']>=2 && $U['eninbox']!=0){
2144 $stmt=$db->prepare('SELECT COUNT(*) FROM ' . PREFIX . 'inbox WHERE recipient=?;');
2145 $stmt->execute([$U['nickname']]);
2146 $tmp=$stmt->fetch(PDO::FETCH_NUM);
2147 if($tmp[0]>0){
2148 echo '<p>'.form('inbox').submit(sprintf($I['inboxmsgs'], $tmp[0])).'</form></p>';
2149 }
2150 }
2151 if($U['status']>=5 && get_setting('guestaccess')==3){
2152 $result=$db->query('SELECT COUNT(*) FROM ' . PREFIX . 'sessions WHERE entry=0 AND status=1;');
2153 $temp=$result->fetch(PDO::FETCH_NUM);
2154 if($temp[0]>0){
2155 echo '<p>';
2156 echo form('admin', 'approve');
2157 echo submit(sprintf($I['approveguests'], $temp[0])).'</form></p>';
2158 }
2159 }
2160 echo '</span>';
2161}
2162function print_chatters(){
2163 global $I, $U, $db, $language;
2164 if(!$U['hidechatters']){
2165 echo '<div id="chatters"><table><tr>';
2166 $stmt=$db->prepare('SELECT nickname, style, status FROM ' . PREFIX . 'sessions WHERE entry!=0 AND status>0 AND incognito=0 AND nickname NOT IN (SELECT ign FROM '. PREFIX . 'ignored WHERE ignby=? UNION SELECT ignby FROM '. PREFIX . 'ignored WHERE ign=?) ORDER BY status DESC, lastpost DESC;');
2167 $stmt->execute([$U['nickname'], $U['nickname']]);
2168 $nc=substr(time(), -6);
2169 $G=$M=[];
2170 while($user=$stmt->fetch(PDO::FETCH_NUM)){
2171 $link="<a href=\"$_SERVER[SCRIPT_NAME]?action=post&session=$U[session]&lang=$language&nc=$nc&sendto=".htmlspecialchars($user[0]).'" target="post">'.style_this(htmlspecialchars($user[0]), $user[1]).'</a>';
2172 if($user[2]<=2){
2173 $G[]=$link;
2174 }else{
2175 $M[]=$link;
2176 }
2177 }
2178 if(!empty($M)){
2179 echo "<th>$I[members]:</th><td> </td><td>".implode(' ', $M).'</td>';
2180 if(!empty($G)){
2181 echo '<td> </td>';
2182 }
2183 }
2184 if(!empty($G)){
2185 echo "<th>$I[guests]:</th><td> </td><td>".implode(' ', $G).'</td>';
2186 }
2187 echo '</tr></table></div>';
2188 }
2189}
2190
2191// session management
2192
2193function create_session($setup, $nickname, $password){
2194 global $I, $U;
2195 $U['nickname']=preg_replace('/\s/', '', $nickname);
2196 if(check_member($password)){
2197 if($setup && $U['status']>=7){
2198 $U['incognito']=1;
2199 }
2200 $U['entry']=$U['lastpost']=time();
2201 }else{
2202 add_user_defaults($password);
2203 check_captcha(isset($_REQUEST['challenge']) ? $_REQUEST['challenge'] : '', isset($_REQUEST['captcha']) ? $_REQUEST['captcha'] : '');
2204 $ga=(int) get_setting('guestaccess');
2205 if(!valid_nick($U['nickname'])){
2206 send_error(sprintf($I['invalnick'], get_setting('maxname'), get_setting('nickregex')));
2207 }
2208 if(!valid_pass($password)){
2209 send_error(sprintf($I['invalpass'], get_setting('minpass'), get_setting('passregex')));
2210 }
2211 if($ga===0){
2212 send_error($I['noguests']);
2213 }elseif($ga===3){
2214 $U['entry']=0;
2215 }
2216 if(get_setting('englobalpass')!=0 && isset($_REQUEST['globalpass']) && $_REQUEST['globalpass']!=get_setting('globalpass')){
2217 send_error($I['wrongglobalpass']);
2218 }
2219 }
2220 write_new_session($password);
2221}
2222
2223function check_captcha($challenge, $captcha_code){
2224 global $I, $db, $memcached;
2225 $captcha=(int) get_setting('captcha');
2226 if($captcha!==0){
2227 if(empty($challenge)){
2228 send_error($I['wrongcaptcha']);
2229 }
2230 if(MEMCACHED){
2231 if(!$code=$memcached->get(DBNAME . '-' . PREFIX . "captcha-$_REQUEST[challenge]")){
2232 send_error($I['captchaexpire']);
2233 }
2234 $memcached->delete(DBNAME . '-' . PREFIX . "captcha-$_REQUEST[challenge]");
2235 }else{
2236 $stmt=$db->prepare('SELECT code FROM ' . PREFIX . 'captcha WHERE id=?;');
2237 $stmt->execute([$challenge]);
2238 $stmt->bindColumn(1, $code);
2239 if(!$stmt->fetch(PDO::FETCH_BOUND)){
2240 send_error($I['captchaexpire']);
2241 }
2242 $time=time();
2243 $stmt=$db->prepare('DELETE FROM ' . PREFIX . 'captcha WHERE id=? OR time<(?-(SELECT value FROM ' . PREFIX . "settings WHERE setting='captchatime'));");
2244 $stmt->execute([$challenge, $time]);
2245 }
2246 if($captcha_code!==$code){
2247 if($captcha!==3 || strrev($captcha_code)!==$code){
2248 send_error($I['wrongcaptcha']);
2249 }
2250 }
2251 }
2252}
2253
2254function write_new_session($password){
2255 global $I, $U, $db;
2256 $stmt=$db->prepare('SELECT * FROM ' . PREFIX . 'sessions WHERE nickname=?;');
2257 $stmt->execute([$U['nickname']]);
2258 if($temp=$stmt->fetch(PDO::FETCH_ASSOC)){
2259 // check whether alrady logged in
2260 if(password_verify($password, $temp['passhash'])){
2261 $U=$temp;
2262 check_kicked();
2263 setcookie(COOKIENAME, $U['session']);
2264 }else{
2265 send_error("$I[userloggedin]<br>$I[wrongpass]");
2266 }
2267 }else{
2268 // create new session
2269 $stmt=$db->prepare('SELECT null FROM ' . PREFIX . 'sessions WHERE session=?;');
2270 do{
2271 if(function_exists('random_bytes')){
2272 $U['session']=bin2hex(random_bytes(16));
2273 }else{
2274 $U['session']=md5(uniqid($U['nickname'], true).mt_rand());
2275 }
2276 $stmt->execute([$U['session']]);
2277 }while($stmt->fetch(PDO::FETCH_NUM)); // check for hash collision
2278 if(isset($_SERVER['HTTP_USER_AGENT'])){
2279 $useragent=htmlspecialchars($_SERVER['HTTP_USER_AGENT']);
2280 }else{
2281 $useragent='';
2282 }
2283 if(get_setting('trackip')){
2284 $ip=$_SERVER['REMOTE_ADDR'];
2285 }else{
2286 $ip='';
2287 }
2288 $stmt=$db->prepare('INSERT INTO ' . PREFIX . 'sessions (session, nickname, status, refresh, style, lastpost, passhash, useragent, bgcolour, entry, timestamps, embed, incognito, ip, nocache, tz, eninbox, sortupdown, hidechatters, nocache_old) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);');
2289 $stmt->execute([$U['session'], $U['nickname'], $U['status'], $U['refresh'], $U['style'], $U['lastpost'], $U['passhash'], $useragent, $U['bgcolour'], $U['entry'], $U['timestamps'], $U['embed'], $U['incognito'], $ip, $U['nocache'], $U['tz'], $U['eninbox'], $U['sortupdown'], $U['hidechatters'], $U['nocache_old']]);
2290 setcookie(COOKIENAME, $U['session']);
2291 if($U['status']>=3 && !$U['incognito']){
2292 add_system_message(sprintf(get_setting('msgenter'), style_this(htmlspecialchars($U['nickname']), $U['style'])));
2293 }
2294 }
2295}
2296
2297function approve_session(){
2298 global $db;
2299 if(isset($_REQUEST['what'])){
2300 if($_REQUEST['what']==='allowchecked' && isset($_REQUEST['csid'])){
2301 $stmt=$db->prepare('UPDATE ' . PREFIX . 'sessions SET entry=lastpost WHERE nickname=?;');
2302 foreach($_REQUEST['csid'] as $nick){
2303 $stmt->execute([$nick]);
2304 }
2305 }elseif($_REQUEST['what']==='allowall' && isset($_REQUEST['alls'])){
2306 $stmt=$db->prepare('UPDATE ' . PREFIX . 'sessions SET entry=lastpost WHERE nickname=?;');
2307 foreach($_REQUEST['alls'] as $nick){
2308 $stmt->execute([$nick]);
2309 }
2310 }elseif($_REQUEST['what']==='denychecked' && isset($_REQUEST['csid'])){
2311 $time=60*(get_setting('kickpenalty')-get_setting('guestexpire'))+time();
2312 $stmt=$db->prepare('UPDATE ' . PREFIX . 'sessions SET lastpost=?, status=0, kickmessage=? WHERE nickname=? AND status=1;');
2313 foreach($_REQUEST['csid'] as $nick){
2314 $stmt->execute([$time, $_REQUEST['kickmessage'], $nick]);
2315 }
2316 }elseif($_REQUEST['what']==='denyall' && isset($_REQUEST['alls'])){
2317 $time=60*(get_setting('kickpenalty')-get_setting('guestexpire'))+time();
2318 $stmt=$db->prepare('UPDATE ' . PREFIX . 'sessions SET lastpost=?, status=0, kickmessage=? WHERE nickname=? AND status=1;');
2319 foreach($_REQUEST['alls'] as $nick){
2320 $stmt->execute([$time, $_REQUEST['kickmessage'], $nick]);
2321 }
2322 }
2323 }
2324}
2325
2326function check_login(){
2327 global $I, $U, $db;
2328 $ga=(int) get_setting('guestaccess');
2329 if(isset($_REQUEST['session'])){
2330 parse_sessions();
2331 }
2332 if(isset($U['session'])){
2333 check_kicked();
2334 }elseif(get_setting('englobalpass')==1 && (!isset($_REQUEST['globalpass']) || $_REQUEST['globalpass']!=get_setting('globalpass'))){
2335 send_error($I['wrongglobalpass']);
2336 }elseif(!isset($_REQUEST['nick']) || !isset($_REQUEST['pass'])){
2337 send_login();
2338 }else{
2339 if($ga===4){
2340 send_chat_disabled();
2341 }
2342 if(!empty($_REQUEST['regpass']) && $_REQUEST['regpass']!==$_REQUEST['pass']){
2343 send_error($I['noconfirm']);
2344 }
2345 create_session(false, $_REQUEST['nick'], $_REQUEST['pass']);
2346 if(!empty($_REQUEST['regpass'])){
2347 $guestreg=(int) get_setting('guestreg');
2348 if($guestreg===1){
2349 register_guest(2, $_REQUEST['nick']);
2350 $U['status']=2;
2351 }elseif($guestreg===2){
2352 register_guest(3, $_REQUEST['nick']);
2353 $U['status']=3;
2354 }
2355 }
2356 }
2357 if($U['status']==1){
2358 if($ga===2 || $ga===3){
2359 $stmt=$db->prepare('UPDATE ' . PREFIX . 'sessions SET entry=0 WHERE session=?;');
2360 $stmt->execute([$U['session']]);
2361 send_waiting_room();
2362 }
2363 }
2364}
2365
2366function kill_session(){
2367 global $U, $db;
2368 parse_sessions();
2369 check_expired();
2370 check_kicked();
2371 setcookie(COOKIENAME, false);
2372 $_REQUEST['session']='';
2373 $stmt=$db->prepare('DELETE FROM ' . PREFIX . 'sessions WHERE session=?;');
2374 $stmt->execute([$U['session']]);
2375 if($U['status']>=3 && !$U['incognito']){
2376 add_system_message(sprintf(get_setting('msgexit'), style_this(htmlspecialchars($U['nickname']), $U['style'])));
2377 }
2378}
2379
2380function kick_chatter($names, $mes, $purge){
2381 global $U, $db;
2382 $lonick='';
2383 $time=60*(get_setting('kickpenalty')-get_setting('guestexpire'))+time();
2384 $check=$db->prepare('SELECT style, entry FROM ' . PREFIX . 'sessions WHERE nickname=? AND status!=0 AND (status<? OR nickname=?);');
2385 $stmt=$db->prepare('UPDATE ' . PREFIX . 'sessions SET lastpost=?, status=0, kickmessage=? WHERE nickname=?;');
2386 $all=false;
2387 if($names[0]==='s &'){
2388 $tmp=$db->query('SELECT nickname FROM ' . PREFIX . 'sessions WHERE status=1;');
2389 $names=[];
2390 while($name=$tmp->fetch(PDO::FETCH_NUM)){
2391 $names[]=$name[0];
2392 }
2393 $all=true;
2394 }
2395 $i=0;
2396 foreach($names as $name){
2397 $check->execute([$name, $U['status'], $U['nickname']]);
2398 if($temp=$check->fetch(PDO::FETCH_ASSOC)){
2399 $stmt->execute([$time, $mes, $name]);
2400 if($purge){
2401 del_all_messages($name, $temp['entry']);
2402 }
2403 $lonick.=style_this(htmlspecialchars($name), $temp['style']).', ';
2404 ++$i;
2405 }
2406 }
2407 if($i>0){
2408 if($all){
2409 add_system_message(get_setting('msgallkick'));
2410 }else{
2411 $lonick=substr($lonick, 0, -2);
2412 if($i>1){
2413 add_system_message(sprintf(get_setting('msgmultikick'), $lonick));
2414 }else{
2415 add_system_message(sprintf(get_setting('msgkick'), $lonick));
2416 }
2417 }
2418 return true;
2419 }
2420 return false;
2421}
2422
2423function logout_chatter($names){
2424 global $U, $db;
2425 $stmt=$db->prepare('DELETE FROM ' . PREFIX . 'sessions WHERE nickname=? AND status<?;');
2426 if($names[0]==='s &'){
2427 $tmp=$db->query('SELECT nickname FROM ' . PREFIX . 'sessions WHERE status=1;');
2428 $names=[];
2429 while($name=$tmp->fetch(PDO::FETCH_NUM)){
2430 $names[]=$name[0];
2431 }
2432 }
2433 foreach($names as $name){
2434 $stmt->execute([$name, $U['status']]);
2435 }
2436}
2437
2438function check_session(){
2439 global $U;
2440 parse_sessions();
2441 check_expired();
2442 check_kicked();
2443 if($U['entry']==0){
2444 send_waiting_room();
2445 }
2446}
2447
2448function check_expired(){
2449 global $I, $U;
2450 if(!isset($U['session'])){
2451 setcookie(COOKIENAME, false);
2452 $_REQUEST['session']='';
2453 send_error($I['expire']);
2454 }
2455}
2456
2457function get_count_mods(){
2458 global $db;
2459 $c=$db->query('SELECT COUNT(*) FROM ' . PREFIX . 'sessions WHERE status>=5')->fetch(PDO::FETCH_NUM);
2460 return $c[0];
2461}
2462
2463function check_kicked(){
2464 global $I, $U;
2465 if($U['status']==0){
2466 setcookie(COOKIENAME, false);
2467 $_REQUEST['session']='';
2468 send_error("$I[kicked]<br>$U[kickmessage]");
2469 }
2470}
2471
2472function get_nowchatting(){
2473 global $I, $db;
2474 parse_sessions();
2475 $stmt=$db->query('SELECT COUNT(*) FROM ' . PREFIX . 'sessions WHERE entry!=0 AND status>0 AND incognito=0;');
2476 $count=$stmt->fetch(PDO::FETCH_NUM);
2477 echo '<div id="chatters">'.sprintf($I['curchat'], $count[0]).'<br>';
2478 if(!get_setting('hidechatters')){
2479 $stmt=$db->query('SELECT nickname, style FROM ' . PREFIX . 'sessions WHERE entry!=0 AND status>0 AND incognito=0 ORDER BY status DESC, lastpost DESC;');
2480 while($user=$stmt->fetch(PDO::FETCH_NUM)){
2481 echo style_this(htmlspecialchars($user[0]), $user[1]).' ';
2482 }
2483 }
2484 echo '</div>';
2485}
2486
2487function parse_sessions(){
2488 global $U, $db;
2489 // look for our session
2490 if(isset($_REQUEST['session'])){
2491 $stmt=$db->prepare('SELECT * FROM ' . PREFIX . 'sessions WHERE session=?;');
2492 $stmt->execute([$_REQUEST['session']]);
2493 if($tmp=$stmt->fetch(PDO::FETCH_ASSOC)){
2494 $U=$tmp;
2495 }
2496 }
2497 set_default_tz();
2498}
2499
2500// member handling
2501
2502function check_member($password){
2503 global $I, $U, $db;
2504 $stmt=$db->prepare('SELECT * FROM ' . PREFIX . 'members WHERE nickname=?;');
2505 $stmt->execute([$U['nickname']]);
2506 if($temp=$stmt->fetch(PDO::FETCH_ASSOC)){
2507 if(get_setting('dismemcaptcha')==0){
2508 check_captcha(isset($_REQUEST['challenge']) ? $_REQUEST['challenge'] : '', isset($_REQUEST['captcha']) ? $_REQUEST['captcha'] : '');
2509 }
2510 if($temp['passhash']===md5(sha1(md5($U['nickname'].$password)))){
2511 // old hashing method, update on the fly
2512 $temp['passhash']=password_hash($password, PASSWORD_DEFAULT);
2513 $stmt=$db->prepare('UPDATE ' . PREFIX . 'members SET passhash=? WHERE nickname=?;');
2514 $stmt->execute([$temp['passhash'], $U['nickname']]);
2515 }
2516 if(password_verify($password, $temp['passhash'])){
2517 $U=$temp;
2518 $stmt=$db->prepare('UPDATE ' . PREFIX . 'members SET lastlogin=? WHERE nickname=?;');
2519 $stmt->execute([time(), $U['nickname']]);
2520 return true;
2521 }else{
2522 send_error("$I[regednick]<br>$I[wrongpass]");
2523 }
2524 }
2525 return false;
2526}
2527
2528function delete_account(){
2529 global $U, $db;
2530 if($U['status']<8){
2531 $stmt=$db->prepare('UPDATE ' . PREFIX . 'sessions SET status=1, incognito=0 WHERE nickname=?;');
2532 $stmt->execute([$U['nickname']]);
2533 $stmt=$db->prepare('DELETE FROM ' . PREFIX . 'members WHERE nickname=?;');
2534 $stmt->execute([$U['nickname']]);
2535 $stmt=$db->prepare('DELETE FROM ' . PREFIX . 'inbox WHERE recipient=?;');
2536 $stmt->execute([$U['nickname']]);
2537 $stmt=$db->prepare('DELETE FROM ' . PREFIX . 'notes WHERE type=2 AND editedby=?;');
2538 $stmt->execute([$U['nickname']]);
2539 $U['status']=1;
2540 }
2541}
2542
2543function register_guest($status, $nick){
2544 global $I, $U, $db;
2545 $stmt=$db->prepare('SELECT style FROM ' . PREFIX . 'members WHERE nickname=?');
2546 $stmt->execute([$nick]);
2547 if($tmp=$stmt->fetch(PDO::FETCH_NUM)){
2548 return sprintf($I['alreadyreged'], style_this(htmlspecialchars($nick), $tmp[0]));
2549 }
2550 $stmt=$db->prepare('SELECT * FROM ' . PREFIX . 'sessions WHERE nickname=? AND status=1;');
2551 $stmt->execute([$nick]);
2552 if($reg=$stmt->fetch(PDO::FETCH_ASSOC)){
2553 $reg['status']=$status;
2554 $stmt=$db->prepare('UPDATE ' . PREFIX . 'sessions SET status=? WHERE session=?;');
2555 $stmt->execute([$reg['status'], $reg['session']]);
2556 }else{
2557 return sprintf($I['cantreg'], htmlspecialchars($nick));
2558 }
2559 $stmt=$db->prepare('INSERT INTO ' . PREFIX . 'members (nickname, passhash, status, refresh, bgcolour, regedby, timestamps, embed, style, incognito, nocache, tz, eninbox, sortupdown, hidechatters, nocache_old) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);');
2560 $stmt->execute([$reg['nickname'], $reg['passhash'], $reg['status'], $reg['refresh'], $reg['bgcolour'], $U['nickname'], $reg['timestamps'], $reg['embed'], $reg['style'], $reg['incognito'], $reg['nocache'], $reg['tz'], $reg['eninbox'], $reg['sortupdown'], $reg['hidechatters'], $reg['nocache_old']]);
2561 if($reg['status']==3){
2562 add_system_message(sprintf(get_setting('msgmemreg'), style_this(htmlspecialchars($reg['nickname']), $reg['style'])));
2563 }else{
2564 add_system_message(sprintf(get_setting('msgsureg'), style_this(htmlspecialchars($reg['nickname']), $reg['style'])));
2565 }
2566 return sprintf($I['successreg'], style_this(htmlspecialchars($reg['nickname']), $reg['style']));
2567}
2568
2569function register_new($nick, $pass){
2570 global $I, $U, $db;
2571 $nick=preg_replace('/\s/', '', $nick);
2572 if(empty($nick)){
2573 return '';
2574 }
2575 $stmt=$db->prepare('SELECT null FROM ' . PREFIX . 'sessions WHERE nickname=?');
2576 $stmt->execute([$nick]);
2577 if($stmt->fetch(PDO::FETCH_NUM)){
2578 return sprintf($I['cantreg'], htmlspecialchars($nick));
2579 }
2580 if(!valid_nick($nick)){
2581 return sprintf($I['invalnick'], get_setting('maxname'), get_setting('nickregex'));
2582 }
2583 if(!valid_pass($pass)){
2584 return sprintf($I['invalpass'], get_setting('minpass'), get_setting('passregex'));
2585 }
2586 $stmt=$db->prepare('SELECT null FROM ' . PREFIX . 'members WHERE nickname=?');
2587 $stmt->execute([$nick]);
2588 if($stmt->fetch(PDO::FETCH_NUM)){
2589 return sprintf($I['alreadyreged'], htmlspecialchars($nick));
2590 }
2591 $reg=[
2592 'nickname' =>$nick,
2593 'passhash' =>password_hash($pass, PASSWORD_DEFAULT),
2594 'status' =>3,
2595 'refresh' =>get_setting('defaultrefresh'),
2596 'bgcolour' =>get_setting('colbg'),
2597 'regedby' =>$U['nickname'],
2598 'timestamps' =>get_setting('timestamps'),
2599 'style' =>'color:#'.get_setting('coltxt').';',
2600 'embed' =>1,
2601 'incognito' =>0,
2602 'nocache' =>0,
2603 'nocache_old' =>1,
2604 'tz' =>get_setting('defaulttz'),
2605 'eninbox' =>0,
2606 'sortupdown' =>get_setting('sortupdown'),
2607 'hidechatters' =>get_setting('hidechatters'),
2608 ];
2609 $stmt=$db->prepare('INSERT INTO ' . PREFIX . 'members (nickname, passhash, status, refresh, bgcolour, regedby, timestamps, style, embed, incognito, nocache, tz, eninbox, sortupdown, hidechatters, nocache_old) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);');
2610 $stmt->execute([$reg['nickname'], $reg['passhash'], $reg['status'], $reg['refresh'], $reg['bgcolour'], $reg['regedby'], $reg['timestamps'], $reg['style'], $reg['embed'], $reg['incognito'], $reg['nocache'], $reg['tz'], $reg['eninbox'], $reg['sortupdown'], $reg['hidechatters'], $reg['nocache_old']]);
2611 return sprintf($I['successreg'], htmlspecialchars($reg['nickname']));
2612}
2613
2614function change_status($nick, $status){
2615 global $I, $U, $db;
2616 if(empty($nick)){
2617 return '';
2618 }elseif($U['status']<=$status || !preg_match('/^[023567\-]$/', $status)){
2619 return sprintf($I['cantchgstat'], htmlspecialchars($nick));
2620 }
2621 $stmt=$db->prepare('SELECT incognito, style FROM ' . PREFIX . 'members WHERE nickname=? AND status<?;');
2622 $stmt->execute([$nick, $U['status']]);
2623 if(!$old=$stmt->fetch(PDO::FETCH_NUM)){
2624 return sprintf($I['cantchgstat'], htmlspecialchars($nick));
2625 }
2626 if($_REQUEST['set']==='-'){
2627 $stmt=$db->prepare('DELETE FROM ' . PREFIX . 'members WHERE nickname=?;');
2628 $stmt->execute([$nick]);
2629 $stmt=$db->prepare('UPDATE ' . PREFIX . 'sessions SET status=1, incognito=0 WHERE nickname=?;');
2630 $stmt->execute([$nick]);
2631 return sprintf($I['succdel'], style_this(htmlspecialchars($nick), $old[1]));
2632 }else{
2633 if($status<5){
2634 $old[0]=0;
2635 }
2636 $stmt=$db->prepare('UPDATE ' . PREFIX . 'members SET status=?, incognito=? WHERE nickname=?;');
2637 $stmt->execute([$status, $old[0], $nick]);
2638 $stmt=$db->prepare('UPDATE ' . PREFIX . 'sessions SET status=?, incognito=? WHERE nickname=?;');
2639 $stmt->execute([$status, $old[0], $nick]);
2640 return sprintf($I['succchg'], style_this(htmlspecialchars($nick), $old[1]));
2641 }
2642}
2643
2644function passreset($nick, $pass){
2645 global $I, $U, $db;
2646 if(empty($nick)){
2647 return '';
2648 }
2649 $stmt=$db->prepare('SELECT null FROM ' . PREFIX . 'members WHERE nickname=? AND status<?;');
2650 $stmt->execute([$nick, $U['status']]);
2651 if($stmt->fetch(PDO::FETCH_ASSOC)){
2652 $passhash=password_hash($pass, PASSWORD_DEFAULT);
2653 $stmt=$db->prepare('UPDATE ' . PREFIX . 'members SET passhash=? WHERE nickname=?;');
2654 $stmt->execute([$passhash, $nick]);
2655 $stmt=$db->prepare('UPDATE ' . PREFIX . 'sessions SET passhash=? WHERE nickname=?;');
2656 $stmt->execute([$passhash, $nick]);
2657 return sprintf($I['succpassreset'], htmlspecialchars($nick));
2658 }else{
2659 return sprintf($I['cantresetpass'], htmlspecialchars($nick));
2660 }
2661}
2662
2663function amend_profile(){
2664 global $U;
2665 if(isset($_REQUEST['refresh'])){
2666 $U['refresh']=$_REQUEST['refresh'];
2667 }
2668 if($U['refresh']<5){
2669 $U['refresh']=5;
2670 }elseif($U['refresh']>150){
2671 $U['refresh']=150;
2672 }
2673 if(preg_match('/^#([a-f0-9]{6})$/i', $_REQUEST['colour'], $match)){
2674 $colour=$match[1];
2675 }else{
2676 preg_match('/#([0-9a-f]{6})/i', $U['style'], $matches);
2677 $colour=$matches[1];
2678 }
2679 if(preg_match('/^#([a-f0-9]{6})$/i', $_REQUEST['bgcolour'], $match)){
2680 $U['bgcolour']=$match[1];
2681 }
2682 $U['style']="color:#$colour;";
2683 if($U['status']>=3){
2684 $F=load_fonts();
2685 if(isset($F[$_REQUEST['font']])){
2686 $U['style'].=$F[$_REQUEST['font']];
2687 }
2688 if(isset($_REQUEST['small'])){
2689 $U['style'].='font-size:smaller;';
2690 }
2691 if(isset($_REQUEST['italic'])){
2692 $U['style'].='font-style:italic;';
2693 }
2694 if(isset($_REQUEST['bold'])){
2695 $U['style'].='font-weight:bold;';
2696 }
2697 }
2698 if($U['status']>=5 && isset($_REQUEST['incognito']) && get_setting('incognito')){
2699 $U['incognito']=1;
2700 }else{
2701 $U['incognito']=0;
2702 }
2703 if(isset($_REQUEST['tz'])){
2704 $tzs=timezone_identifiers_list();
2705 if(in_array($_REQUEST['tz'], $tzs)){
2706 $U['tz']=$_REQUEST['tz'];
2707 }
2708 }
2709 if(isset($_REQUEST['eninbox']) && $_REQUEST['eninbox']>=0 && $_REQUEST['eninbox']<=5){
2710 $U['eninbox']=$_REQUEST['eninbox'];
2711 }
2712 $bool_settings=['timestamps', 'embed', 'nocache', 'sortupdown', 'hidechatters'];
2713 foreach($bool_settings as $setting){
2714 if(isset($_REQUEST[$setting])){
2715 $U[$setting]=1;
2716 }else{
2717 $U[$setting]=0;
2718 }
2719 }
2720}
2721
2722function save_profile(){
2723 global $I, $U, $db;
2724 amend_profile();
2725 $stmt=$db->prepare('UPDATE ' . PREFIX . 'sessions SET refresh=?, style=?, bgcolour=?, timestamps=?, embed=?, incognito=?, nocache=?, tz=?, eninbox=?, sortupdown=?, hidechatters=? WHERE session=?;');
2726 $stmt->execute([$U['refresh'], $U['style'], $U['bgcolour'], $U['timestamps'], $U['embed'], $U['incognito'], $U['nocache'], $U['tz'], $U['eninbox'], $U['sortupdown'], $U['hidechatters'], $U['session']]);
2727 if($U['status']>=2){
2728 $stmt=$db->prepare('UPDATE ' . PREFIX . 'members SET refresh=?, bgcolour=?, timestamps=?, embed=?, incognito=?, style=?, nocache=?, tz=?, eninbox=?, sortupdown=?, hidechatters=? WHERE nickname=?;');
2729 $stmt->execute([$U['refresh'], $U['bgcolour'], $U['timestamps'], $U['embed'], $U['incognito'], $U['style'], $U['nocache'], $U['tz'], $U['eninbox'], $U['sortupdown'], $U['hidechatters'], $U['nickname']]);
2730 }
2731 if(!empty($_REQUEST['unignore'])){
2732 $stmt=$db->prepare('DELETE FROM ' . PREFIX . 'ignored WHERE ign=? AND ignby=?;');
2733 $stmt->execute([$_REQUEST['unignore'], $U['nickname']]);
2734 }
2735 if(!empty($_REQUEST['ignore'])){
2736 $stmt=$db->prepare('SELECT null FROM ' . PREFIX . 'messages WHERE poster=? AND poster NOT IN (SELECT ign FROM ' . PREFIX . 'ignored WHERE ignby=?);');
2737 $stmt->execute([$_REQUEST['ignore'], $U['nickname']]);
2738 if($U['nickname']!==$_REQUEST['ignore'] && $stmt->fetch(PDO::FETCH_NUM)){
2739 $stmt=$db->prepare('INSERT INTO ' . PREFIX . 'ignored (ign, ignby) VALUES (?, ?);');
2740 $stmt->execute([$_REQUEST['ignore'], $U['nickname']]);
2741 }
2742 }
2743 if($U['status']>1 && !empty($_REQUEST['newpass'])){
2744 if(!valid_pass($_REQUEST['newpass'])){
2745 return sprintf($I['invalpass'], get_setting('minpass'), get_setting('passregex'));
2746 }
2747 if(!isset($_REQUEST['oldpass'])){
2748 $_REQUEST['oldpass']='';
2749 }
2750 if(!isset($_REQUEST['confirmpass'])){
2751 $_REQUEST['confirmpass']='';
2752 }
2753 if($_REQUEST['newpass']!==$_REQUEST['confirmpass']){
2754 return $I['noconfirm'];
2755 }else{
2756 $U['newhash']=password_hash($_REQUEST['newpass'], PASSWORD_DEFAULT);
2757 }
2758 if(!password_verify($_REQUEST['oldpass'], $U['passhash'])){
2759 return $I['wrongpass'];
2760 }
2761 $U['passhash']=$U['newhash'];
2762 $stmt=$db->prepare('UPDATE ' . PREFIX . 'sessions SET passhash=? WHERE session=?;');
2763 $stmt->execute([$U['passhash'], $U['session']]);
2764 $stmt=$db->prepare('UPDATE ' . PREFIX . 'members SET passhash=? WHERE nickname=?;');
2765 $stmt->execute([$U['passhash'], $U['nickname']]);
2766 }
2767 if($U['status']>1 && !empty($_REQUEST['newnickname'])){
2768 $msg=set_new_nickname();
2769 if($msg!==''){
2770 return $msg;
2771 }
2772 }
2773 return $I['succprofile'];
2774}
2775
2776function set_new_nickname(){
2777 global $I, $U, $db;
2778 $_REQUEST['newnickname']=preg_replace('/\s/', '', $_REQUEST['newnickname']);
2779 if(!valid_nick($_REQUEST['newnickname'])){
2780 return sprintf($I['invalnick'], get_setting('maxname'), get_setting('nickregex'));
2781 }
2782 $stmt=$db->prepare('SELECT id FROM ' . PREFIX . 'sessions WHERE nickname=? UNION SELECT id FROM ' . PREFIX . 'members WHERE nickname=?;');
2783 $stmt->execute([$_REQUEST['newnickname'], $_REQUEST['newnickname']]);
2784 if($stmt->fetch(PDO::FETCH_NUM)){
2785 return $I['nicknametaken'];
2786 }else{
2787 $stmt=$db->prepare('UPDATE ' . PREFIX . 'members SET nickname=? WHERE nickname=?;');
2788 $stmt->execute([$_REQUEST['newnickname'], $U['nickname']]);
2789 $stmt=$db->prepare('UPDATE ' . PREFIX . 'sessions SET nickname=? WHERE nickname=?;');
2790 $stmt->execute([$_REQUEST['newnickname'], $U['nickname']]);
2791 $stmt=$db->prepare('UPDATE ' . PREFIX . 'messages SET poster=? WHERE poster=?;');
2792 $stmt->execute([$_REQUEST['newnickname'], $U['nickname']]);
2793 $stmt=$db->prepare('UPDATE ' . PREFIX . 'messages SET recipient=? WHERE recipient=?;');
2794 $stmt->execute([$_REQUEST['newnickname'], $U['nickname']]);
2795 $stmt=$db->prepare('UPDATE ' . PREFIX . 'ignored SET ignby=? WHERE ignby=?;');
2796 $stmt->execute([$_REQUEST['newnickname'], $U['nickname']]);
2797 $stmt=$db->prepare('UPDATE ' . PREFIX . 'ignored SET ign=? WHERE ign=?;');
2798 $stmt->execute([$_REQUEST['newnickname'], $U['nickname']]);
2799 $stmt=$db->prepare('UPDATE ' . PREFIX . 'inbox SET poster=? WHERE poster=?;');
2800 $stmt->execute([$_REQUEST['newnickname'], $U['nickname']]);
2801 $stmt=$db->prepare('UPDATE ' . PREFIX . 'notes SET editedby=? WHERE editedby=?;');
2802 $stmt->execute([$_REQUEST['newnickname'], $U['nickname']]);
2803 $U['nickname']=$_REQUEST['newnickname'];
2804 }
2805 return '';
2806}
2807
2808//sets default settings for guests
2809function add_user_defaults($password){
2810 global $U;
2811 $U['refresh']=get_setting('defaultrefresh');
2812 $U['bgcolour']=get_setting('colbg');
2813 if(!isset($_REQUEST['colour']) || !preg_match('/^[a-f0-9]{6}$/i', $_REQUEST['colour']) || abs(greyval($_REQUEST['colour'])-greyval(get_setting('colbg')))<75){
2814 do{
2815 $colour=sprintf('%06X', mt_rand(0, 16581375));
2816 }while(abs(greyval($colour)-greyval(get_setting('colbg')))<75);
2817 }else{
2818 $colour=$_REQUEST['colour'];
2819 }
2820 $U['style']="color:#$colour;";
2821 $U['timestamps']=get_setting('timestamps');
2822 $U['embed']=1;
2823 $U['incognito']=0;
2824 $U['status']=1;
2825 $U['nocache']=get_setting('sortupdown');
2826 if($U['nocache']){
2827 $U['nocache_old']=0;
2828 }else{
2829 $U['nocache_old']=1;
2830 }
2831 $U['tz']=get_setting('defaulttz');
2832 $U['eninbox']=0;
2833 $U['sortupdown']=get_setting('sortupdown');
2834 $U['hidechatters']=get_setting('hidechatters');
2835 $U['passhash']=password_hash($password, PASSWORD_DEFAULT);
2836 $U['entry']=$U['lastpost']=time();
2837}
2838
2839// message handling
2840
2841function validate_input(){
2842 global $U, $db;
2843 $inbox=false;
2844 $maxmessage=get_setting('maxmessage');
2845 $message=mb_substr($_REQUEST['message'], 0, $maxmessage);
2846 $rejected=mb_substr($_REQUEST['message'], $maxmessage);
2847 if($U['postid']===$_REQUEST['postid']){// ignore double post=reload from browser or proxy
2848 $message='';
2849 }elseif((time()-$U['lastpost'])<=1){// time between posts too short, reject!
2850 $rejected=$_REQUEST['message'];
2851 $message='';
2852 }
2853 if(!empty($rejected)){
2854 $rejected=trim($rejected);
2855 $rejected=htmlspecialchars($rejected);
2856 }
2857 $message=htmlspecialchars($message);
2858 $message=preg_replace("/(\r?\n|\r\n?)/u", '<br>', $message);
2859 if(isset($_REQUEST['multi'])){
2860 $message=preg_replace('/\s*<br>/u', '<br>', $message);
2861 $message=preg_replace('/<br>(<br>)+/u', '<br><br>', $message);
2862 $message=preg_replace('/<br><br>\s*$/u', '<br>', $message);
2863 $message=preg_replace('/^<br>\s*$/u', '', $message);
2864 }else{
2865 $message=str_replace('<br>', ' ', $message);
2866 }
2867 $message=trim($message);
2868 $message=preg_replace('/\s+/u', ' ', $message);
2869 $recipient='';
2870 if($_REQUEST['sendto']==='s *'){
2871 $poststatus=1;
2872 $displaysend=sprintf(get_setting('msgsendall'), style_this(htmlspecialchars($U['nickname']), $U['style']));
2873 }elseif($_REQUEST['sendto']==='s ?' && $U['status']>=3){
2874 $poststatus=3;
2875 $displaysend=sprintf(get_setting('msgsendmem'), style_this(htmlspecialchars($U['nickname']), $U['style']));
2876 }elseif($_REQUEST['sendto']==='s #' && $U['status']>=5){
2877 $poststatus=5;
2878 $displaysend=sprintf(get_setting('msgsendmod'), style_this(htmlspecialchars($U['nickname']), $U['style']));
2879 }elseif($_REQUEST['sendto']==='s &' && $U['status']>=6){
2880 $poststatus=6;
2881 $displaysend=sprintf(get_setting('msgsendadm'), style_this(htmlspecialchars($U['nickname']), $U['style']));
2882 }else{ // known nick in room?
2883 if(get_setting('disablepm')){
2884 //PMs disabled
2885 return;
2886 }
2887 $stmt=$db->prepare('SELECT null FROM ' . PREFIX . 'ignored WHERE (ignby=? AND ign=?) OR (ign=? AND ignby=?);');
2888 $stmt->execute([$_REQUEST['sendto'], $U['nickname'], $_REQUEST['sendto'], $U['nickname']]);
2889 if($stmt->fetch(PDO::FETCH_NUM)){
2890 //ignored
2891 return;
2892 }
2893 $tmp=false;
2894 $stmt=$db->prepare('SELECT s.style, 0 AS inbox FROM ' . PREFIX . 'sessions AS s LEFT JOIN ' . PREFIX . 'members AS m ON (m.nickname=s.nickname) WHERE s.nickname=? AND (s.incognito=0 OR (m.eninbox!=0 AND m.eninbox<=?));');
2895 $stmt->execute([$_REQUEST['sendto'], $U['status']]);
2896 if(!$tmp=$stmt->fetch(PDO::FETCH_ASSOC)){
2897 $stmt=$db->prepare('SELECT style, 1 AS inbox FROM ' . PREFIX . 'members WHERE nickname=? AND eninbox!=0 AND eninbox<=?;');
2898 $stmt->execute([$_REQUEST['sendto'], $U['status']]);
2899 if(!$tmp=$stmt->fetch(PDO::FETCH_ASSOC)){
2900 //nickname left or disabled offline inbox for us
2901 return;
2902 }
2903 }
2904 $recipient=$_REQUEST['sendto'];
2905 $poststatus=9;
2906 $displaysend=sprintf(get_setting('msgsendprv'), style_this(htmlspecialchars($U['nickname']), $U['style']), style_this(htmlspecialchars($recipient), $tmp['style']));
2907 $inbox=$tmp['inbox'];
2908 }
2909 if($poststatus!==9 && preg_match('~^/me~iu', $message)){
2910 $displaysend=style_this(htmlspecialchars("$U[nickname] "), $U['style']);
2911 $message=preg_replace("~^/me\s?~iu", '', $message);
2912 }
2913 $message=apply_filter($message, $poststatus, $U['nickname']);
2914 $message=create_hotlinks($message);
2915 $message=apply_linkfilter($message);
2916 if(isset($_FILES['file']) && get_setting('enfileupload')){
2917 if($_FILES['file']['error']===UPLOAD_ERR_OK && $_FILES['file']['size']<=(1024*get_setting('maxuploadsize'))){
2918 $hash=sha1_file($_FILES['file']['tmp_name']);
2919 $name=htmlspecialchars($_FILES['file']['name']);
2920 $message=sprintf(get_setting('msgattache'), "<a class=\"attachement\" href=\"$_SERVER[SCRIPT_NAME]?action=download&id=$hash\" target=\"_blank\">$name</a>", $message);
2921 }
2922 }
2923 if(add_message($message, $recipient, $U['nickname'], $U['status'], $poststatus, $displaysend, $U['style'])){
2924 $U['lastpost']=time();
2925 $stmt=$db->prepare('UPDATE ' . PREFIX . 'sessions SET lastpost=?, postid=? WHERE session=?;');
2926 $stmt->execute([$U['lastpost'], $_REQUEST['postid'], $U['session']]);
2927 $stmt=$db->prepare('SELECT id FROM ' . PREFIX . 'messages WHERE poster=? ORDER BY id DESC LIMIT 1;');
2928 $stmt->execute([$U['nickname']]);
2929 $id=$stmt->fetch(PDO::FETCH_NUM);
2930 if($inbox && $id){
2931 $newmessage=[
2932 'postdate' =>time(),
2933 'poster' =>$U['nickname'],
2934 'recipient' =>$recipient,
2935 'text' =>"<span class=\"usermsg\">$displaysend".style_this($message, $U['style']).'</span>'
2936 ];
2937 if(MSGENCRYPTED){
2938 $newmessage['text']=openssl_encrypt($newmessage['text'], 'aes-256-cbc', ENCRYPTKEY, 0, '1234567890123456');
2939 }
2940 $stmt=$db->prepare('INSERT INTO ' . PREFIX . 'inbox (postdate, postid, poster, recipient, text) VALUES(?, ?, ?, ?, ?)');
2941 $stmt->execute([$newmessage['postdate'], $id[0], $newmessage['poster'], $newmessage['recipient'], $newmessage['text']]);
2942 }
2943 if(isset($hash) && $id){
2944 if(!empty($_FILES['file']['type']) && preg_match('~^[a-z0-9/\-\.\+]*$~i', $_FILES['file']['type'])){
2945 $type=$_FILES['file']['type'];
2946 }else{
2947 $type='application/octet-stream';
2948 }
2949 $stmt=$db->prepare('INSERT INTO ' . PREFIX . 'files (postid, hash, filename, type, data) VALUES (?, ?, ?, ?, ?);');
2950 $stmt->execute([$id[0], $hash, str_replace('"', '\"', $_FILES['file']['name']), $type, base64_encode(file_get_contents($_FILES['file']['tmp_name']))]);
2951 unlink($_FILES['file']['tmp_name']);
2952 }
2953 }
2954 return $rejected;
2955}
2956
2957function apply_filter($message, $poststatus, $nickname){
2958 global $I, $U;
2959 $message=str_replace('<br>', "\n", $message);
2960 $message=apply_mention($message);
2961 $filters=get_filters();
2962 foreach($filters as $filter){
2963 if($poststatus!==9 || !$filter['allowinpm']){
2964 if($filter['cs']){
2965 $message=preg_replace("/$filter[match]/u", $filter['replace'], $message, -1, $count);
2966 }else{
2967 $message=preg_replace("/$filter[match]/iu", $filter['replace'], $message, -1, $count);
2968 }
2969 }
2970 if(isset($count) && $count>0 && $filter['kick'] && ($U['status']<5 || get_setting('filtermodkick'))){
2971 kick_chatter([$nickname], $filter['replace'], false);
2972 setcookie(COOKIENAME, false);
2973 $_REQUEST['session']='';
2974 send_error("$I[kicked]<br>$filter[replace]");
2975 }
2976 }
2977 $message=str_replace("\n", '<br>', $message);
2978 return $message;
2979}
2980
2981function apply_linkfilter($message){
2982 $filters=get_linkfilters();
2983 foreach($filters as $filter){
2984 $message=preg_replace_callback("/<a href=\"([^\"]+)\" target=\"_blank\">(.*?(?=<\/a>))<\/a>/iu",
2985 function ($matched) use(&$filter){
2986 return "<a href=\"$matched[1]\" target=\"_blank\">".preg_replace("/$filter[match]/iu", $filter['replace'], $matched[2]).'</a>';
2987 }
2988 , $message);
2989 }
2990 $redirect=get_setting('redirect');
2991 if(get_setting('imgembed')){
2992 $message=preg_replace_callback('/\[img\]\s?<a href="([^"]+)" target="_blank">(.*?(?=<\/a>))<\/a>/iu',
2993 function ($matched){
2994 return str_ireplace('[/img]', '', "<br><a href=\"$matched[1]\" target=\"_blank\"><img src=\"$matched[1]\"></a><br>");
2995 }
2996 , $message);
2997 }
2998 if(empty($redirect)){
2999 $redirect="$_SERVER[SCRIPT_NAME]?action=redirect&url=";
3000 }
3001 if(get_setting('forceredirect')){
3002 $message=preg_replace_callback('/<a href="([^"]+)" target="_blank">(.*?(?=<\/a>))<\/a>/u',
3003 function ($matched) use($redirect){
3004 return "<a href=\"$redirect".rawurlencode($matched[1])."\" target=\"_blank\">$matched[2]</a>";
3005 }
3006 , $message);
3007 }elseif(preg_match_all('/<a href="([^"]+)" target="_blank">(.*?(?=<\/a>))<\/a>/u', $message, $matches)){
3008 foreach($matches[1] as $match){
3009 if(!preg_match('~^http(s)?://~u', $match)){
3010 $message=preg_replace_callback('/<a href="('.preg_quote($match, '/').')\" target=\"_blank\">(.*?(?=<\/a>))<\/a>/u',
3011 function ($matched) use($redirect){
3012 return "<a href=\"$redirect".rawurlencode($matched[1])."\" target=\"_blank\">$matched[2]</a>";
3013 }
3014 , $message);
3015 }
3016 }
3017 }
3018 return $message;
3019}
3020
3021function create_hotlinks($message){
3022 //Make hotlinks for URLs, redirect through dereferrer script to prevent session leakage
3023 // 1. all explicit schemes with whatever xxx://yyyyyyy
3024 $message=preg_replace('~(^|[^\w"])(\w+://[^\s<>]+)~iu', "$1<<$2>>", $message);
3025 // 2. valid URLs without scheme:
3026 $message=preg_replace('~((?:[^\s<>]*:[^\s<>]*@)?[a-z0-9\-]+(?:\.[a-z0-9\-]+)+(?::\d*)?/[^\s<>]*)(?![^<>]*>)~iu', "<<$1>>", $message); // server/path given
3027 $message=preg_replace('~((?:[^\s<>]*:[^\s<>]*@)?[a-z0-9\-]+(?:\.[a-z0-9\-]+)+:\d+)(?![^<>]*>)~iu', "<<$1>>", $message); // server:port given
3028 $message=preg_replace('~([^\s<>]*:[^\s<>]*@[a-z0-9\-]+(?:\.[a-z0-9\-]+)+(?::\d+)?)(?![^<>]*>)~iu', "<<$1>>", $message); // au:th@server given
3029 // 3. likely servers without any hints but not filenames like *.rar zip exe etc.
3030 $message=preg_replace('~((?:[a-z0-9\-]+\.)*(?:[a-z2-7]{55}d|[a-z2-7]{16})\.onion)(?![^<>]*>)~iu', "<<$1>>", $message);// *.onion
3031 $message=preg_replace('~([a-z0-9\-]+(?:\.[a-z0-9\-]+)+(?:\.(?!rar|zip|exe|gz|7z|bat|doc)[a-z]{2,}))(?=[^a-z0-9\-\.]|$)(?![^<>]*>)~iu', "<<$1>>", $message);// xxx.yyy.zzz
3032 // Convert every <<....>> into proper links:
3033 $message=preg_replace_callback('/<<([^<>]+)>>/u',
3034 function ($matches){
3035 if(strpos($matches[1], '://')===false){
3036 return "<a href=\"http://$matches[1]\" target=\"_blank\">$matches[1]</a>";
3037 }else{
3038 return "<a href=\"$matches[1]\" target=\"_blank\">$matches[1]</a>";
3039 }
3040 }
3041 , $message);
3042 return $message;
3043}
3044
3045function apply_mention($message){
3046 return preg_replace_callback('/\@([^\s]+)/iu', function ($matched){
3047 global $db;
3048 $nick=htmlspecialchars_decode($matched[1]);
3049 $rest='';
3050 for($i=0;$i<=3;++$i){
3051 //match case-sensitive present nicknames
3052 $stmt=$db->prepare('SELECT style FROM ' . PREFIX . 'sessions WHERE nickname=?;');
3053 $stmt->execute([$nick]);
3054 if($tmp=$stmt->fetch(PDO::FETCH_NUM)){
3055 return style_this(htmlspecialchars("@$nick"), $tmp[0]).$rest;
3056 }
3057 //match case-insensitive present nicknames
3058 $stmt=$db->prepare('SELECT style FROM ' . PREFIX . 'sessions WHERE LOWER(nickname)=LOWER(?);');
3059 $stmt->execute([$nick]);
3060 if($tmp=$stmt->fetch(PDO::FETCH_NUM)){
3061 return style_this(htmlspecialchars("@$nick"), $tmp[0]).$rest;
3062 }
3063 //match case-sensitive members
3064 $stmt=$db->prepare('SELECT style FROM ' . PREFIX . 'members WHERE nickname=?;');
3065 $stmt->execute([$nick]);
3066 if($tmp=$stmt->fetch(PDO::FETCH_NUM)){
3067 return style_this(htmlspecialchars("@$nick"), $tmp[0]).$rest;
3068 }
3069 //match case-insensitive members
3070 $stmt=$db->prepare('SELECT style FROM ' . PREFIX . 'members WHERE LOWER(nickname)=LOWER(?);');
3071 $stmt->execute([$nick]);
3072 if($tmp=$stmt->fetch(PDO::FETCH_NUM)){
3073 return style_this(htmlspecialchars("@$nick"), $tmp[0]).$rest;
3074 }
3075 if(strlen($nick)===1){
3076 break;
3077 }
3078 $rest=mb_substr($nick, -1).$rest;
3079 $nick=mb_substr($nick, 0, -1);
3080 }
3081 return $matched[0];
3082 }, $message);
3083}
3084
3085function add_message($message, $recipient, $poster, $delstatus, $poststatus, $displaysend, $style){
3086 global $db;
3087 if($message===''){
3088 return false;
3089 }
3090 $newmessage=[
3091 'postdate' =>time(),
3092 'poststatus' =>$poststatus,
3093 'poster' =>$poster,
3094 'recipient' =>$recipient,
3095 'text' =>"<span class=\"usermsg\">$displaysend".style_this($message, $style).'</span>',
3096 'delstatus' =>$delstatus
3097 ];
3098 //prevent posting the same message twice, if no other message was posted in-between.
3099 $stmt=$db->prepare('SELECT id FROM ' . PREFIX . 'messages WHERE poststatus=? AND poster=? AND recipient=? AND text=? AND id IN (SELECT * FROM (SELECT id FROM ' . PREFIX . 'messages ORDER BY id DESC LIMIT 1) AS t);');
3100 $stmt->execute([$newmessage['poststatus'], $newmessage['poster'], $newmessage['recipient'], $newmessage['text']]);
3101 if($stmt->fetch(PDO::FETCH_NUM)){
3102 return false;
3103 }
3104 write_message($newmessage);
3105 return true;
3106}
3107
3108function add_system_message($mes){
3109 if($mes===''){
3110 return;
3111 }
3112 $sysmessage=[
3113 'postdate' =>time(),
3114 'poststatus' =>1,
3115 'poster' =>'',
3116 'recipient' =>'',
3117 'text' =>"<span class=\"sysmsg\">$mes</span>",
3118 'delstatus' =>4
3119 ];
3120 write_message($sysmessage);
3121}
3122
3123function write_message($message){
3124 global $db;
3125 if(MSGENCRYPTED){
3126 $message['text']=openssl_encrypt($message['text'], 'aes-256-cbc', ENCRYPTKEY, 0, '1234567890123456');
3127 }
3128 $stmt=$db->prepare('INSERT INTO ' . PREFIX . 'messages (postdate, poststatus, poster, recipient, text, delstatus) VALUES (?, ?, ?, ?, ?, ?);');
3129 $stmt->execute([$message['postdate'], $message['poststatus'], $message['poster'], $message['recipient'], $message['text'], $message['delstatus']]);
3130 if($message['poststatus']<9 && get_setting('sendmail')){
3131 $subject='New Chat message';
3132 $headers='From: '.get_setting('mailsender')."\r\nX-Mailer: PHP/".phpversion()."\r\nContent-Type: text/html; charset=UTF-8\r\n";
3133 $body='<html><body style="background-color:#'.get_setting('colbg').';color:#'.get_setting('coltxt').";\">$message[text]</body></html>";
3134 mail(get_setting('mailreceiver'), $subject, $body, $headers);
3135 }
3136}
3137
3138function clean_room(){
3139 global $db;
3140 $db->query('DELETE FROM ' . PREFIX . 'messages;');
3141 add_system_message(sprintf(get_setting('msgclean'), get_setting('chatname')));
3142}
3143
3144function clean_selected($status, $nick){
3145 global $db;
3146 if(isset($_REQUEST['mid'])){
3147 $stmt=$db->prepare('DELETE FROM ' . PREFIX . 'messages WHERE id=? AND (poster=? OR recipient=? OR (poststatus<? AND delstatus<?));');
3148 foreach($_REQUEST['mid'] as $mid){
3149 $stmt->execute([$mid, $nick, $nick, $status, $status]);
3150 }
3151 }
3152}
3153
3154function clean_inbox_selected(){
3155 global $U, $db;
3156 if(isset($_REQUEST['mid'])){
3157 $stmt=$db->prepare('DELETE FROM ' . PREFIX . 'inbox WHERE id=? AND recipient=?;');
3158 foreach($_REQUEST['mid'] as $mid){
3159 $stmt->execute([$mid, $U['nickname']]);
3160 }
3161 }
3162}
3163
3164function del_all_messages($nick, $entry){
3165 global $db;
3166 if($nick==''){
3167 return;
3168 }
3169 $stmt=$db->prepare('DELETE FROM ' . PREFIX . 'messages WHERE poster=? AND postdate>=?;');
3170 $stmt->execute([$nick, $entry]);
3171 $stmt=$db->prepare('DELETE FROM ' . PREFIX . 'inbox WHERE poster=? AND postdate>=?;');
3172 $stmt->execute([$nick, $entry]);
3173}
3174
3175function del_last_message(){
3176 global $U, $db;
3177 if($U['status']>1){
3178 $entry=0;
3179 }else{
3180 $entry=$U['entry'];
3181 }
3182 $stmt=$db->prepare('SELECT id FROM ' . PREFIX . 'messages WHERE poster=? AND postdate>=? ORDER BY id DESC LIMIT 1;');
3183 $stmt->execute([$U['nickname'], $entry]);
3184 if($id=$stmt->fetch(PDO::FETCH_NUM)){
3185 $stmt=$db->prepare('DELETE FROM ' . PREFIX . 'messages WHERE id=?;');
3186 $stmt->execute($id);
3187 $stmt=$db->prepare('DELETE FROM ' . PREFIX . 'inbox WHERE postid=?;');
3188 $stmt->execute($id);
3189 }
3190}
3191
3192function print_messages($delstatus=0){
3193 global $U, $db;
3194 $dateformat=get_setting('dateformat');
3195 if(!$U['embed'] && get_setting('imgembed')){
3196 $removeEmbed=true;
3197 }else{
3198 $removeEmbed=false;
3199 }
3200 if($U['timestamps'] && !empty($dateformat)){
3201 $timestamps=true;
3202 }else{
3203 $timestamps=false;
3204 }
3205 if($U['sortupdown']){
3206 $direction='ASC';
3207 }else{
3208 $direction='DESC';
3209 }
3210 if($U['status']>1){
3211 $entry=0;
3212 }else{
3213 $entry=$U['entry'];
3214 }
3215 echo '<div id="messages">';
3216 if($delstatus>0){
3217 $stmt=$db->prepare('SELECT postdate, id, text FROM ' . PREFIX . 'messages WHERE '.
3218 "(poststatus<? AND delstatus<?) OR ((poster=? OR recipient=?) AND postdate>=?) ORDER BY id $direction;");
3219 $stmt->execute([$U['status'], $delstatus, $U['nickname'], $U['nickname'], $entry]);
3220 while($message=$stmt->fetch(PDO::FETCH_ASSOC)){
3221 prepare_message_print($message, $removeEmbed);
3222 echo "<div class=\"msg\"><label><input type=\"checkbox\" name=\"mid[]\" value=\"$message[id]\">";
3223 if($timestamps){
3224 echo ' <small>'.date($dateformat, $message['postdate']).' - </small>';
3225 }
3226 echo " $message[text]</label></div>";
3227 }
3228 }else{
3229 $stmt=$db->prepare('SELECT id, postdate, text FROM ' . PREFIX . 'messages WHERE (poststatus<=? OR '.
3230 '(poststatus=9 AND ( (poster=? AND recipient NOT IN (SELECT ign FROM ' . PREFIX . 'ignored WHERE ignby=?) ) OR recipient=?) AND postdate>=?)'.
3231 ') AND poster NOT IN (SELECT ign FROM ' . PREFIX . "ignored WHERE ignby=?) ORDER BY id $direction;");
3232 $stmt->execute([$U['status'], $U['nickname'], $U['nickname'], $U['nickname'], $entry, $U['nickname']]);
3233 while($message=$stmt->fetch(PDO::FETCH_ASSOC)){
3234 prepare_message_print($message, $removeEmbed);
3235 echo '<div class="msg">';
3236 if($timestamps){
3237 echo '<small>'.date($dateformat, $message['postdate']).' - </small>';
3238 }
3239 echo "$message[text]</div>";
3240 }
3241 }
3242 echo '</div>';
3243}
3244
3245function prepare_message_print(&$message, $removeEmbed){
3246 if(MSGENCRYPTED){
3247 $message['text']=openssl_decrypt($message['text'], 'aes-256-cbc', ENCRYPTKEY, 0, '1234567890123456');
3248 }
3249 if($removeEmbed){
3250 $message['text']=preg_replace_callback('/<img src="([^"]+)"><\/a>/u',
3251 function ($matched){
3252 return "$matched[1]</a>";
3253 }
3254 , $message['text']);
3255 }
3256}
3257
3258// this and that
3259
3260function send_headers(){
3261 header('Content-Type: text/html; charset=UTF-8');
3262 header('Pragma: no-cache');
3263 header('Cache-Control: no-cache, no-store, must-revalidate, max-age=0');
3264 header('Expires: 0');
3265 header('Referrer-Policy: no-referrer');
3266 header('Content-Security-Policy: referrer never');
3267 if($_SERVER['REQUEST_METHOD']==='HEAD'){
3268 exit; // headers sent, no further processing needed
3269 }
3270}
3271
3272function save_setup($C){
3273 global $db;
3274 //sanity checks and escaping
3275 foreach($C['msg_settings'] as $setting){
3276 $_REQUEST[$setting]=htmlspecialchars($_REQUEST[$setting]);
3277 }
3278 foreach($C['number_settings'] as $setting){
3279 settype($_REQUEST[$setting], 'int');
3280 }
3281 foreach($C['colour_settings'] as $setting){
3282 if(preg_match('/^#([a-f0-9]{6})$/i', $_REQUEST[$setting], $match)){
3283 $_REQUEST[$setting]=$match[1];
3284 }else{
3285 unset($_REQUEST[$setting]);
3286 }
3287 }
3288 settype($_REQUEST['guestaccess'], 'int');
3289 if(!preg_match('/^[01234]$/', $_REQUEST['guestaccess'])){
3290 unset($_REQUEST['guestaccess']);
3291 }elseif($_REQUEST['guestaccess']==4){
3292 $db->exec('DELETE FROM ' . PREFIX . 'sessions WHERE status<7;');
3293 }
3294 settype($_REQUEST['englobalpass'], 'int');
3295 settype($_REQUEST['captcha'], 'int');
3296 settype($_REQUEST['dismemcaptcha'], 'int');
3297 settype($_REQUEST['guestreg'], 'int');
3298 if(isset($_REQUEST['defaulttz'])){
3299 $tzs=timezone_identifiers_list();
3300 if(!in_array($_REQUEST['defaulttz'], $tzs)){
3301 unset($_REQUEST['defualttz']);
3302 }
3303 }
3304 $_REQUEST['rulestxt']=preg_replace("/(\r?\n|\r\n?)/u", '<br>', $_REQUEST['rulestxt']);
3305 $_REQUEST['chatname']=htmlspecialchars($_REQUEST['chatname']);
3306 $_REQUEST['redirect']=htmlspecialchars($_REQUEST['redirect']);
3307 if($_REQUEST['memberexpire']<5){
3308 $_REQUEST['memberexpire']=5;
3309 }
3310 if($_REQUEST['captchatime']<30){
3311 $_REQUEST['memberexpire']=30;
3312 }
3313 if($_REQUEST['defaultrefresh']<5){
3314 $_REQUEST['defaultrefresh']=5;
3315 }elseif($_REQUEST['defaultrefresh']>150){
3316 $_REQUEST['defaultrefresh']=150;
3317 }
3318 if($_REQUEST['maxname']<1){
3319 $_REQUEST['maxname']=1;
3320 }elseif($_REQUEST['maxname']>50){
3321 $_REQUEST['maxname']=50;
3322 }
3323 if($_REQUEST['maxmessage']<1){
3324 $_REQUEST['maxmessage']=1;
3325 }elseif($_REQUEST['maxmessage']>16000){
3326 $_REQUEST['maxmessage']=16000;
3327 }
3328 if($_REQUEST['numnotes']<1){
3329 $_REQUEST['numnotes']=1;
3330 }
3331 if(!valid_regex($_REQUEST['nickregex'])){
3332 unset($_REQUEST['nickregex']);
3333 }
3334 if(!valid_regex($_REQUEST['passregex'])){
3335 unset($_REQUEST['passregex']);
3336 }
3337 //save values
3338 foreach($C['settings'] as $setting){
3339 if(isset($_REQUEST[$setting])){
3340 update_setting($setting, $_REQUEST[$setting]);
3341 }
3342 }
3343}
3344
3345function set_default_tz(){
3346 global $U;
3347 if(isset($U['tz'])){
3348 date_default_timezone_set($U['tz']);
3349 }else{
3350 date_default_timezone_set(get_setting('defaulttz'));
3351 }
3352}
3353
3354function valid_admin(){
3355 global $U;
3356 if(isset($_REQUEST['session'])){
3357 parse_sessions();
3358 }
3359 if(!isset($U['session']) && isset($_REQUEST['nick']) && isset($_REQUEST['pass'])){
3360 create_session(true, $_REQUEST['nick'], $_REQUEST['pass']);
3361 }
3362 if(isset($U['status'])){
3363 if($U['status']>=7){
3364 return true;
3365 }
3366 send_access_denied();
3367 }
3368 return false;
3369}
3370
3371function valid_nick($nick){
3372 $len=mb_strlen($nick);
3373 if($len<1 || $len>get_setting('maxname')){
3374 return false;
3375 }
3376 return preg_match('/'.get_setting('nickregex').'/u', $nick);
3377}
3378
3379function valid_pass($pass){
3380 if(mb_strlen($pass)<get_setting('minpass')){
3381 return false;
3382 }
3383 return preg_match('/'.get_setting('passregex').'/u', $pass);
3384}
3385
3386function valid_regex(&$regex){
3387 $regex=preg_replace('~(^|[^\\\\])/~', "$1\/u", $regex); // Escape "/" if not yet escaped
3388 return (@preg_match("/$_REQUEST[match]/u", '') !== false);
3389}
3390
3391function get_timeout($lastpost, $expire){
3392 $s=($lastpost+60*$expire)-time();
3393 $m=floor($s/60);
3394 $s%=60;
3395 if($s<10){
3396 $s="0$s";
3397 }
3398 if($m>60){
3399 $h=floor($m/60);
3400 $m%=60;
3401 if($m<10){
3402 $m="0$m";
3403 }
3404 echo "$h:$m:$s";
3405 }else{
3406 echo "$m:$s";
3407 }
3408}
3409
3410function print_colours(){
3411 global $I;
3412 // Prints a short list with selected named HTML colours and filters out illegible text colours for the given background.
3413 // It's a simple comparison of weighted grey values. This is not very accurate but gets the job done well enough.
3414 // name=>[colour, greyval(colour)]
3415 $colours=['Beige'=>['F5F5DC', 242.25], 'Black'=>['000000', 0], 'Blue'=>['0000FF', 28.05], 'BlueViolet'=>['8A2BE2', 91.63], 'Brown'=>['A52A2A', 78.9], 'Cyan'=>['00FFFF', 178.5], 'DarkBlue'=>['00008B', 15.29], 'DarkGreen'=>['006400', 59], 'DarkRed'=>['8B0000', 41.7], 'DarkViolet'=>['9400D3', 67.61], 'DeepSkyBlue'=>['00BFFF', 140.74], 'Gold'=>['FFD700', 203.35], 'Grey'=>['808080', 128], 'Green'=>['008000', 75.52], 'HotPink'=>['FF69B4', 158.25], 'Indigo'=>['4B0082', 36.8], 'LightBlue'=>['ADD8E6', 204.64], 'LightGreen'=>['90EE90', 199.46], 'LimeGreen'=>['32CD32', 141.45], 'Magenta'=>['FF00FF', 104.55], 'Olive'=>['808000', 113.92], 'Orange'=>['FFA500', 173.85], 'OrangeRed'=>['FF4500', 117.21], 'Purple'=>['800080', 52.48], 'Red'=>['FF0000', 76.5], 'RoyalBlue'=>['4169E1', 106.2], 'SeaGreen'=>['2E8B57', 105.38], 'Sienna'=>['A0522D', 101.33], 'Silver'=>['C0C0C0', 192], 'Tan'=>['D2B48C', 184.6], 'Teal'=>['008080', 89.6], 'Violet'=>['EE82EE', 174.28], 'White'=>['FFFFFF', 255], 'Yellow'=>['FFFF00', 226.95], 'YellowGreen'=>['9ACD32', 172.65]];
3416 $greybg=greyval(get_setting('colbg'));
3417 foreach($colours as $name=>$colour){
3418 if(abs($greybg-$colour[1])>75){
3419 echo "<option value=\"$colour[0]\" style=\"color:#$colour[0];\">$I[$name]</option>";
3420 }
3421 }
3422}
3423
3424function greyval($colour){
3425 return hexdec(substr($colour, 0, 2))*.3+hexdec(substr($colour, 2, 2))*.59+hexdec(substr($colour, 4, 2))*.11;
3426}
3427
3428function style_this($text, $styleinfo){
3429 return "<span style=\"$styleinfo\">$text</span>";
3430}
3431
3432function check_init(){
3433 global $db;
3434 return @$db->query('SELECT null FROM ' . PREFIX . 'settings LIMIT 1;');
3435}
3436
3437// run every minute doing various database cleanup task
3438function cron(){
3439 global $db;
3440 $time=time();
3441 if(get_setting('nextcron')>$time){
3442 return;
3443 }
3444 update_setting('nextcron', $time+10);
3445 // delete old sessions
3446 $stmt=$db->prepare('DELETE FROM ' . PREFIX . 'sessions WHERE (status<=2 AND lastpost<(?-60*(SELECT value FROM ' . PREFIX . "settings WHERE setting='guestexpire'))) OR (status>2 AND lastpost<(?-60*(SELECT value FROM " . PREFIX . "settings WHERE setting='memberexpire')));");
3447 $stmt->execute([$time, $time]);
3448 // delete old messages
3449 $limit=get_setting('messagelimit');
3450 $stmt=$db->query('SELECT id FROM ' . PREFIX . "messages WHERE poststatus=1 ORDER BY id DESC LIMIT 1 OFFSET $limit;");
3451 if($id=$stmt->fetch(PDO::FETCH_NUM)){
3452 $stmt=$db->prepare('DELETE FROM ' . PREFIX . 'messages WHERE id<=?;');
3453 $stmt->execute($id);
3454 }
3455 $stmt=$db->prepare('DELETE FROM ' . PREFIX . 'messages WHERE id IN (SELECT * FROM (SELECT id FROM ' . PREFIX . 'messages WHERE postdate<(?-60*(SELECT value FROM ' . PREFIX . "settings WHERE setting='messageexpire'))) AS t);");
3456 $stmt->execute([$time]);
3457 // delete expired ignored people
3458 $result=$db->query('SELECT id FROM ' . PREFIX . 'ignored WHERE ign NOT IN (SELECT nickname FROM ' . PREFIX . 'sessions UNION SELECT nickname FROM ' . PREFIX . 'members UNION SELECT poster FROM ' . PREFIX . 'messages) OR ignby NOT IN (SELECT nickname FROM ' . PREFIX . 'sessions UNION SELECT nickname FROM ' . PREFIX . 'members UNION SELECT poster FROM ' . PREFIX . 'messages);');
3459 $stmt=$db->prepare('DELETE FROM ' . PREFIX . 'ignored WHERE id=?;');
3460 while($tmp=$result->fetch(PDO::FETCH_NUM)){
3461 $stmt->execute($tmp);
3462 }
3463 // delete files that do not belong to any message
3464 $result=$db->query('SELECT id FROM ' . PREFIX . 'files WHERE postid NOT IN (SELECT id FROM ' . PREFIX . 'messages UNION SELECT postid FROM ' . PREFIX . 'inbox);');
3465 $stmt=$db->prepare('DELETE FROM ' . PREFIX . 'files WHERE id=?;');
3466 while($tmp=$result->fetch(PDO::FETCH_NUM)){
3467 $stmt->execute($tmp);
3468 }
3469 // delete old notes
3470 $limit=get_setting('numnotes');
3471 $db->exec('DELETE FROM ' . PREFIX . 'notes WHERE type!=2 AND id NOT IN (SELECT * FROM ( (SELECT id FROM ' . PREFIX . "notes WHERE type=0 ORDER BY id DESC LIMIT $limit) UNION (SELECT id FROM " . PREFIX . "notes WHERE type=1 ORDER BY id DESC LIMIT $limit) ) AS t);");
3472 $result=$db->query('SELECT editedby, COUNT(*) AS cnt FROM ' . PREFIX . "notes WHERE type=2 GROUP BY editedby HAVING cnt>$limit;");
3473 $stmt=$db->prepare('DELETE FROM ' . PREFIX . 'notes WHERE type=2 AND editedby=? AND id NOT IN (SELECT * FROM (SELECT id FROM ' . PREFIX . "notes WHERE type=2 AND editedby=? ORDER BY id DESC LIMIT $limit) AS t);");
3474 while($tmp=$result->fetch(PDO::FETCH_NUM)){
3475 $stmt->execute([$tmp[0], $tmp[0]]);
3476 }
3477 // delete old captchas
3478 $stmt=$db->prepare('DELETE FROM ' . PREFIX . 'captcha WHERE time<(?-(SELECT value FROM ' . PREFIX . "settings WHERE setting='captchatime'));");
3479 $stmt->execute([$time]);
3480}
3481
3482function destroy_chat($C){
3483 global $I, $db, $memcached;
3484 setcookie(COOKIENAME, false);
3485 $_REQUEST['session']='';
3486 print_start('destory');
3487 $db->exec('DROP TABLE ' . PREFIX . 'captcha;');
3488 $db->exec('DROP TABLE ' . PREFIX . 'files;');
3489 $db->exec('DROP TABLE ' . PREFIX . 'filter;');
3490 $db->exec('DROP TABLE ' . PREFIX . 'ignored;');
3491 $db->exec('DROP TABLE ' . PREFIX . 'inbox;');
3492 $db->exec('DROP TABLE ' . PREFIX . 'linkfilter;');
3493 $db->exec('DROP TABLE ' . PREFIX . 'members;');
3494 $db->exec('DROP TABLE ' . PREFIX . 'messages;');
3495 $db->exec('DROP TABLE ' . PREFIX . 'notes;');
3496 $db->exec('DROP TABLE ' . PREFIX . 'sessions;');
3497 $db->exec('DROP TABLE ' . PREFIX . 'settings;');
3498 if(MEMCACHED){
3499 $memcached->delete(DBNAME . '-' . PREFIX . 'filter');
3500 $memcached->delete(DBANEM . '-' . PREFIX . 'linkfilter');
3501 foreach($C['settings'] as $setting){
3502 $memcached->delete(DBNAME . '-' . PREFIX . "settings-$setting");
3503 }
3504 $memcached->delete(DBNAME . '-' . PREFIX . 'settings-dbversion');
3505 $memcached->delete(DBNAME . '-' . PREFIX . 'settings-msgencrypted');
3506 $memcached->delete(DBNAME . '-' . PREFIX . 'settings-nextcron');
3507 }
3508 echo "<h2>$I[destroyed]</h2><br><br><br>";
3509 echo form('setup').submit($I['init']).'</form>'.credit();
3510 print_end();
3511}
3512
3513function init_chat(){
3514 global $I, $db;
3515 $suwrite='';
3516 if(check_init()){
3517 $suwrite=$I['initdbexist'];
3518 $result=$db->query('SELECT null FROM ' . PREFIX . 'members WHERE status=8;');
3519 if($result->fetch(PDO::FETCH_NUM)){
3520 $suwrite=$I['initsuexist'];
3521 }
3522 }elseif(!preg_match('/^[a-z0-9]{1,20}$/i', $_REQUEST['sunick'])){
3523 $suwrite=sprintf($I['invalnick'], 20, '^[A-Za-z1-9]*$');
3524 }elseif(mb_strlen($_REQUEST['supass'])<5){
3525 $suwrite=sprintf($I['invalpass'], 5, '.*');
3526 }elseif($_REQUEST['supass']!==$_REQUEST['supassc']){
3527 $suwrite=$I['noconfirm'];
3528 }else{
3529 ignore_user_abort(true);
3530 set_time_limit(0);
3531 if(DBDRIVER===0){//MySQL
3532 $memengine=' ENGINE=MEMORY';
3533 $diskengine=' ENGINE=InnoDB';
3534 $charset=' DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin';
3535 $primary='integer PRIMARY KEY AUTO_INCREMENT';
3536 $longtext='longtext';
3537 }elseif(DBDRIVER===1){//PostgreSQL
3538 $memengine='';
3539 $diskengine='';
3540 $charset='';
3541 $primary='serial PRIMARY KEY';
3542 $longtext='text';
3543 }else{//SQLite
3544 $memengine='';
3545 $diskengine='';
3546 $charset='';
3547 $primary='integer PRIMARY KEY';
3548 $longtext='text';
3549 }
3550 $db->exec('CREATE TABLE ' . PREFIX . "captcha (id $primary, time integer NOT NULL, code char(5) NOT NULL)$memengine$charset;");
3551 $db->exec('CREATE TABLE ' . PREFIX . "files (id $primary, postid integer NOT NULL UNIQUE, filename varchar(255) NOT NULL, hash char(40) NOT NULL, type varchar(255) NOT NULL, data $longtext NOT NULL)$diskengine$charset;");
3552 $db->exec('CREATE INDEX ' . PREFIX . 'files_hash ON ' . PREFIX . 'files(hash);');
3553 $db->exec('CREATE TABLE ' . PREFIX . "filter (id $primary, filtermatch varchar(255) NOT NULL, filterreplace text NOT NULL, allowinpm smallint NOT NULL, regex smallint NOT NULL, kick smallint NOT NULL, cs smallint NOT NULL)$diskengine$charset;");
3554 $db->exec('CREATE TABLE ' . PREFIX . "ignored (id $primary, ign varchar(50) NOT NULL, ignby varchar(50) NOT NULL)$diskengine$charset;");
3555 $db->exec('CREATE INDEX ' . PREFIX . 'ign ON ' . PREFIX . 'ignored(ign);');
3556 $db->exec('CREATE INDEX ' . PREFIX . 'ignby ON ' . PREFIX . 'ignored(ignby);');
3557 $db->exec('CREATE TABLE ' . PREFIX . "inbox (id $primary, postdate integer NOT NULL, postid integer NOT NULL UNIQUE, poster varchar(50) NOT NULL, recipient varchar(50) NOT NULL, text text NOT NULL)$diskengine$charset;");
3558 $db->exec('CREATE INDEX ' . PREFIX . 'inbox_poster ON ' . PREFIX . 'inbox(poster);');
3559 $db->exec('CREATE INDEX ' . PREFIX . 'inbox_recipient ON ' . PREFIX . 'inbox(recipient);');
3560 $db->exec('CREATE TABLE ' . PREFIX . "linkfilter (id $primary, filtermatch varchar(255) NOT NULL, filterreplace varchar(255) NOT NULL, regex smallint NOT NULL)$diskengine$charset;");
3561 $db->exec('CREATE TABLE ' . PREFIX . "members (id $primary, nickname varchar(50) NOT NULL UNIQUE, passhash varchar(255) NOT NULL, status smallint NOT NULL, refresh smallint NOT NULL, bgcolour char(6) NOT NULL, regedby varchar(50) DEFAULT '', lastlogin integer DEFAULT 0, timestamps smallint NOT NULL, embed smallint NOT NULL, incognito smallint NOT NULL, style varchar(255) NOT NULL, nocache smallint NOT NULL, tz varchar(255) NOT NULL, eninbox smallint NOT NULL, sortupdown smallint NOT NULL, hidechatters smallint NOT NULL, nocache_old smallint NOT NULL)$diskengine$charset;");
3562 $db->exec('ALTER TABLE ' . PREFIX . 'inbox ADD FOREIGN KEY (recipient) REFERENCES ' . PREFIX . 'members(nickname) ON DELETE CASCADE ON UPDATE CASCADE;');
3563 $db->exec('CREATE TABLE ' . PREFIX . "messages (id $primary, postdate integer NOT NULL, poststatus smallint NOT NULL, poster varchar(50) NOT NULL, recipient varchar(50) NOT NULL, text text NOT NULL, delstatus smallint NOT NULL)$diskengine$charset;");
3564 $db->exec('CREATE INDEX ' . PREFIX . 'poster ON ' . PREFIX . 'messages (poster);');
3565 $db->exec('CREATE INDEX ' . PREFIX . 'recipient ON ' . PREFIX . 'messages(recipient);');
3566 $db->exec('CREATE INDEX ' . PREFIX . 'postdate ON ' . PREFIX . 'messages(postdate);');
3567 $db->exec('CREATE INDEX ' . PREFIX . 'poststatus ON ' . PREFIX . 'messages(poststatus);');
3568 $db->exec('CREATE TABLE ' . PREFIX . "notes (id $primary, type smallint NOT NULL, lastedited integer NOT NULL, editedby varchar(50) NOT NULL, text text NOT NULL)$diskengine$charset;");
3569 $db->exec('CREATE INDEX ' . PREFIX . 'notes_type ON ' . PREFIX . 'notes(type);');
3570 $db->exec('CREATE INDEX ' . PREFIX . 'notes_editedby ON ' . PREFIX . 'notes(editedby);');
3571 $db->exec('CREATE TABLE ' . PREFIX . "sessions (id $primary, session char(32) NOT NULL UNIQUE, nickname varchar(50) NOT NULL UNIQUE, status smallint NOT NULL, refresh smallint NOT NULL, style varchar(255) NOT NULL, lastpost integer NOT NULL, passhash varchar(255) NOT NULL, postid char(6) NOT NULL DEFAULT '000000', useragent varchar(255) NOT NULL, kickmessage varchar(255) DEFAULT '', bgcolour char(6) NOT NULL, entry integer NOT NULL, timestamps smallint NOT NULL, embed smallint NOT NULL, incognito smallint NOT NULL, ip varchar(45) NOT NULL, nocache smallint NOT NULL, tz varchar(255) NOT NULL, eninbox smallint NOT NULL, sortupdown smallint NOT NULL, hidechatters smallint NOT NULL, nocache_old smallint NOT NULL)$memengine$charset;");
3572 $db->exec('CREATE INDEX ' . PREFIX . 'status ON ' . PREFIX . 'sessions(status);');
3573 $db->exec('CREATE INDEX ' . PREFIX . 'lastpost ON ' . PREFIX . 'sessions(lastpost);');
3574 $db->exec('CREATE INDEX ' . PREFIX . 'incognito ON ' . PREFIX . 'sessions(incognito);');
3575 $db->exec('CREATE TABLE ' . PREFIX . "settings (setting varchar(50) NOT NULL PRIMARY KEY, value text NOT NULL)$diskengine$charset;");
3576
3577 $settings=[
3578 ['guestaccess', '0'],
3579 ['globalpass', ''],
3580 ['englobalpass', '0'],
3581 ['captcha', '0'],
3582 ['dateformat', 'm-d H:i:s'],
3583 ['rulestxt', ''],
3584 ['msgencrypted', '0'],
3585 ['dbversion', DBVERSION],
3586 ['css', ''],
3587 ['memberexpire', '60'],
3588 ['guestexpire', '15'],
3589 ['kickpenalty', '10'],
3590 ['entrywait', '120'],
3591 ['messageexpire', '14400'],
3592 ['messagelimit', '150'],
3593 ['maxmessage', 2000],
3594 ['captchatime', '600'],
3595 ['colbg', '000000'],
3596 ['coltxt', 'FFFFFF'],
3597 ['maxname', '20'],
3598 ['minpass', '5'],
3599 ['defaultrefresh', '20'],
3600 ['dismemcaptcha', '0'],
3601 ['suguests', '0'],
3602 ['imgembed', '1'],
3603 ['timestamps', '1'],
3604 ['trackip', '0'],
3605 ['captchachars', '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'],
3606 ['memkick', '1'],
3607 ['forceredirect', '0'],
3608 ['redirect', ''],
3609 ['incognito', '1'],
3610 ['chatname', 'My Chat'],
3611 ['topic', ''],
3612 ['msgsendall', $I['sendallmsg']],
3613 ['msgsendmem', $I['sendmemmsg']],
3614 ['msgsendmod', $I['sendmodmsg']],
3615 ['msgsendadm', $I['sendadmmsg']],
3616 ['msgsendprv', $I['sendprvmsg']],
3617 ['msgenter', $I['entermsg']],
3618 ['msgexit', $I['exitmsg']],
3619 ['msgmemreg', $I['memregmsg']],
3620 ['msgsureg', $I['suregmsg']],
3621 ['msgkick', $I['kickmsg']],
3622 ['msgmultikick', $I['multikickmsg']],
3623 ['msgallkick', $I['allkickmsg']],
3624 ['msgclean', $I['cleanmsg']],
3625 ['numnotes', '3'],
3626 ['mailsender', 'www-data <www-data@localhost>'],
3627 ['mailreceiver', 'Webmaster <webmaster@localhost>'],
3628 ['sendmail', '0'],
3629 ['modfallback', '1'],
3630 ['guestreg', '0'],
3631 ['disablepm', '0'],
3632 ['disabletext', "<h1>$I[disabledtext]</h1>"],
3633 ['defaulttz', 'UTC'],
3634 ['eninbox', '0'],
3635 ['passregex', '.*'],
3636 ['nickregex', '^[A-Za-z0-9]*$'],
3637 ['externalcss', ''],
3638 ['enablegreeting', '0'],
3639 ['sortupdown', '0'],
3640 ['hidechatters', '0'],
3641 ['enfileupload', '0'],
3642 ['msgattache', '%2$s [%1$s]'],
3643 ['maxuploadsize', '1024'],
3644 ['nextcron', '0'],
3645 ['personalnotes', '1'],
3646 ['filtermodkick', '0'],
3647 ];
3648 $stmt=$db->prepare('INSERT INTO ' . PREFIX . 'settings (setting, value) VALUES (?, ?);');
3649 foreach($settings as $pair){
3650 $stmt->execute($pair);
3651 }
3652 $reg=[
3653 'nickname' =>$_REQUEST['sunick'],
3654 'passhash' =>password_hash($_REQUEST['supass'], PASSWORD_DEFAULT),
3655 'status' =>8,
3656 'refresh' =>20,
3657 'bgcolour' =>'000000',
3658 'timestamps' =>1,
3659 'style' =>'color:#FFFFFF;',
3660 'embed' =>1,
3661 'incognito' =>0,
3662 'nocache' =>0,
3663 'nocache_old' =>1,
3664 'tz' =>'UTC',
3665 'eninbox' =>0,
3666 'sortupdown' =>0,
3667 'hidechatters' =>0,
3668 ];
3669 $stmt=$db->prepare('INSERT INTO ' . PREFIX . 'members (nickname, passhash, status, refresh, bgcolour, timestamps, style, embed, incognito, nocache, tz, eninbox, sortupdown, hidechatters, nocache_old) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);');
3670 $stmt->execute([$reg['nickname'], $reg['passhash'], $reg['status'], $reg['refresh'], $reg['bgcolour'], $reg['timestamps'], $reg['style'], $reg['embed'], $reg['incognito'], $reg['nocache'], $reg['tz'], $reg['eninbox'], $reg['sortupdown'], $reg['hidechatters'], $reg['nocache_old']]);
3671 $suwrite=$I['susuccess'];
3672 }
3673 print_start('init');
3674 echo "<h2>$I[init]</h2><br><h3>$I[sulogin]</h3>$suwrite<br><br><br>";
3675 echo form('setup').submit($I['initgosetup']).'</form>'.credit();
3676 print_end();
3677}
3678
3679function update_db(){
3680 global $I, $db, $memcached;
3681 $dbversion=(int) get_setting('dbversion');
3682 $msgencrypted=(bool) get_setting('msgencrypted');
3683 if($dbversion>=DBVERSION && $msgencrypted===MSGENCRYPTED){
3684 return;
3685 }
3686 ignore_user_abort(true);
3687 set_time_limit(0);
3688 if(DBDRIVER===0){//MySQL
3689 $memengine=' ENGINE=MEMORY';
3690 $diskengine=' ENGINE=InnoDB';
3691 $charset=' DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin';
3692 $primary='integer PRIMARY KEY AUTO_INCREMENT';
3693 $longtext='longtext';
3694 }elseif(DBDRIVER===1){//PostgreSQL
3695 $memengine='';
3696 $diskengine='';
3697 $charset='';
3698 $primary='serial PRIMARY KEY';
3699 $longtext='text';
3700 }else{//SQLite
3701 $memengine='';
3702 $diskengine='';
3703 $charset='';
3704 $primary='integer PRIMARY KEY';
3705 $longtext='text';
3706 }
3707 $msg='';
3708 if($dbversion<2){
3709 $db->exec('CREATE TABLE IF NOT EXISTS ' . PREFIX . "ignored (id integer unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT, ignored varchar(50) NOT NULL, `by` varchar(50) NOT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8;");
3710 }
3711 if($dbversion<3){
3712 $db->exec('INSERT INTO ' . PREFIX . "settings (setting, value) VALUES ('rulestxt', '');");
3713 }
3714 if($dbversion<4){
3715 $db->exec('ALTER TABLE ' . PREFIX . 'members ADD incognito smallint NOT NULL;');
3716 }
3717 if($dbversion<5){
3718 $db->exec('INSERT INTO ' . PREFIX . "settings (setting, value) VALUES ('globalpass', '');");
3719 }
3720 if($dbversion<6){
3721 $db->exec('INSERT INTO ' . PREFIX . "settings (setting, value) VALUES ('dateformat', 'm-d H:i:s');");
3722 }
3723 if($dbversion<7){
3724 $db->exec('ALTER TABLE ' . PREFIX . 'captcha ADD code char(5) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;');
3725 }
3726 if($dbversion<8){
3727 $db->exec('INSERT INTO ' . PREFIX . "settings (setting, value) VALUES ('captcha', '0'), ('englobalpass', '0');");
3728 $ga=(int) get_setting('guestaccess');
3729 if($ga===-1){
3730 update_setting('guestaccess', 0);
3731 update_setting('englobalpass', 1);
3732 }elseif($ga===4){
3733 update_setting('guestaccess', 1);
3734 update_setting('englobalpass', 2);
3735 }
3736 }
3737 if($dbversion<9){
3738 $db->exec('INSERT INTO ' . PREFIX . "settings (setting,value) VALUES ('msgencrypted', '0');");
3739 $db->exec('ALTER TABLE ' . PREFIX . 'settings MODIFY value varchar(20000) NOT NULL;');
3740 $db->exec('ALTER TABLE ' . PREFIX . 'messages DROP postid;');
3741 }
3742 if($dbversion<10){
3743 $db->exec('INSERT INTO ' . PREFIX . "settings (setting, value) VALUES ('css', ''), ('memberexpire', '60'), ('guestexpire', '15'), ('kickpenalty', '10'), ('entrywait', '120'), ('messageexpire', '14400'), ('messagelimit', '150'), ('maxmessage', 2000), ('captchatime', '600');");
3744 }
3745 if($dbversion<11){
3746 $db->exec('ALTER TABLE ' , PREFIX . 'captcha CHARACTER SET utf8 COLLATE utf8_bin;');
3747 $db->exec('ALTER TABLE ' . PREFIX . 'filter CHARACTER SET utf8 COLLATE utf8_bin;');
3748 $db->exec('ALTER TABLE ' . PREFIX . 'ignored CHARACTER SET utf8 COLLATE utf8_bin;');
3749 $db->exec('ALTER TABLE ' . PREFIX . 'messages CHARACTER SET utf8 COLLATE utf8_bin;');
3750 $db->exec('ALTER TABLE ' . PREFIX . 'notes CHARACTER SET utf8 COLLATE utf8_bin;');
3751 $db->exec('ALTER TABLE ' . PREFIX . 'settings CHARACTER SET utf8 COLLATE utf8_bin;');
3752 $db->exec('CREATE TABLE ' . PREFIX . "linkfilter (id integer unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT, `match` varchar(255) NOT NULL, `replace` varchar(255) NOT NULL, regex smallint NOT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_bin;");
3753 $db->exec('ALTER TABLE ' . PREFIX . 'members ADD style varchar(255) NOT NULL;');
3754 $result=$db->query('SELECT * FROM ' . PREFIX . 'members;');
3755 $stmt=$db->prepare('UPDATE ' . PREFIX . 'members SET style=? WHERE id=?;');
3756 $F=load_fonts();
3757 while($temp=$result->fetch(PDO::FETCH_ASSOC)){
3758 $style="color:#$temp[colour];";
3759 if(isset($F[$temp['fontface']])){
3760 $style.=$F[$temp['fontface']];
3761 }
3762 if(strpos($temp['fonttags'], 'i')!==false){
3763 $style.='font-style:italic;';
3764 }
3765 if(strpos($temp['fonttags'], 'b')!==false){
3766 $style.='font-weight:bold;';
3767 }
3768 $stmt->execute([$style, $temp['id']]);
3769 }
3770 $db->exec('INSERT INTO ' . PREFIX . "settings (setting, value) VALUES ('colbg', '000000'), ('coltxt', 'FFFFFF'), ('maxname', '20'), ('minpass', '5'), ('defaultrefresh', '20'), ('dismemcaptcha', '0'), ('suguests', '0'), ('imgembed', '1'), ('timestamps', '1'), ('trackip', '0'), ('captchachars', '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'), ('memkick', '1'), ('forceredirect', '0'), ('redirect', ''), ('incognito', '1');");
3771 }
3772 if($dbversion<12){
3773 $db->exec('ALTER TABLE ' . PREFIX . 'captcha MODIFY code char(5) NOT NULL, DROP INDEX id, ADD PRIMARY KEY (id) USING BTREE;');
3774 $db->exec('ALTER TABLE ' . PREFIX . 'captcha ENGINE=MEMORY;');
3775 $db->exec('ALTER TABLE ' . PREFIX . 'filter MODIFY id integer unsigned NOT NULL AUTO_INCREMENT, MODIFY `match` varchar(255) NOT NULL, MODIFY replace varchar(20000) NOT NULL;');
3776 $db->exec('ALTER TABLE ' . PREFIX . 'ignored MODIFY ignored varchar(50) NOT NULL, MODIFY `by` varchar(50) NOT NULL, ADD INDEX(ignored), ADD INDEX(`by`);');
3777 $db->exec('ALTER TABLE ' . PREFIX . 'linkfilter MODIFY match varchar(255) NOT NULL, MODIFY replace varchar(255) NOT NULL;');
3778 $db->exec('ALTER TABLE ' . PREFIX . 'messages MODIFY poster varchar(50) NOT NULL, MODIFY recipient varchar(50) NOT NULL, MODIFY text varchar(20000) NOT NULL, ADD INDEX(poster), ADD INDEX(recipient), ADD INDEX(postdate), ADD INDEX(poststatus);');
3779 $db->exec('ALTER TABLE ' . PREFIX . 'notes MODIFY type char(5) CHARACTER SET latin1 COLLATE latin1_bin NOT NULL, MODIFY editedby varchar(50) NOT NULL, MODIFY text varchar(20000) NOT NULL;');
3780 $db->exec('ALTER TABLE ' . PREFIX . 'settings MODIFY id integer unsigned NOT NULL, MODIFY setting varchar(50) CHARACTER SET latin1 COLLATE latin1_bin NOT NULL, MODIFY value varchar(20000) NOT NULL;');
3781 $db->exec('ALTER TABLE ' . PREFIX . 'settings DROP PRIMARY KEY, DROP id, ADD PRIMARY KEY(setting);');
3782 $db->exec('INSERT INTO ' . PREFIX . "settings (setting, value) VALUES ('chatname', 'My Chat'), ('topic', ''), ('msgsendall', '$I[sendallmsg]'), ('msgsendmem', '$I[sendmemmsg]'), ('msgsendmod', '$I[sendmodmsg]'), ('msgsendadm', '$I[sendadmmsg]'), ('msgsendprv', '$I[sendprvmsg]'), ('numnotes', '3');");
3783 }
3784 if($dbversion<13){
3785 $db->exec('ALTER TABLE ' . PREFIX . 'filter CHANGE `match` filtermatch varchar(255) NOT NULL, CHANGE `replace` filterreplace varchar(20000) NOT NULL;');
3786 $db->exec('ALTER TABLE ' . PREFIX . 'ignored CHANGE ignored ign varchar(50) NOT NULL, CHANGE `by` ignby varchar(50) NOT NULL;');
3787 $db->exec('ALTER TABLE ' . PREFIX . 'linkfilter CHANGE `match` filtermatch varchar(255) NOT NULL, CHANGE `replace` filterreplace varchar(255) NOT NULL;');
3788 }
3789 if($dbversion<14){
3790 if(MEMCACHED){
3791 $memcached->delete(DBNAME . '-' . PREFIX . 'members');
3792 $memcached->delete(DBNAME . '-' . PREFIX . 'ignored');
3793 }
3794 if(DBDRIVER===0){//MySQL - previously had a wrong SQL syntax and the captcha table was not created.
3795 $db->exec('CREATE TABLE IF NOT EXISTS ' . PREFIX . 'captcha (id integer unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT, time integer unsigned NOT NULL, code char(5) NOT NULL) ENGINE=MEMORY DEFAULT CHARSET=utf8 COLLATE=utf8_bin;');
3796 }
3797 }
3798 if($dbversion<15){
3799 $db->exec('INSERT INTO ' . PREFIX . "settings (setting, value) VALUES ('mailsender', 'www-data <www-data@localhost>'), ('mailreceiver', 'Webmaster <webmaster@localhost>'), ('sendmail', '0'), ('modfallback', '1'), ('guestreg', '0');");
3800 }
3801 if($dbversion<17){
3802 $db->exec('ALTER TABLE ' . PREFIX . 'members ADD COLUMN nocache smallint NOT NULL DEFAULT 0;');
3803 }
3804 if($dbversion<18){
3805 $db->exec('INSERT INTO ' . PREFIX . "settings (setting, value) VALUES ('disablepm', '0');");
3806 }
3807 if($dbversion<19){
3808 $db->exec('INSERT INTO ' . PREFIX . "settings (setting, value) VALUES ('disabletext', '<h1>$I[disabledtext]</h1>');");
3809 }
3810 if($dbversion<20){
3811 $db->exec('ALTER TABLE ' . PREFIX . 'members ADD COLUMN tz smallint NOT NULL DEFAULT 0;');
3812 $db->exec('INSERT INTO ' . PREFIX . "settings (setting, value) VALUES ('defaulttz', 'UTC');");
3813 }
3814 if($dbversion<21){
3815 $db->exec('ALTER TABLE ' . PREFIX . 'members ADD COLUMN eninbox smallint NOT NULL DEFAULT 0;');
3816 $db->exec('INSERT INTO ' . PREFIX . "settings (setting, value) VALUES ('eninbox', '0');");
3817 if(DBDRIVER===0){
3818 $db->exec('CREATE TABLE ' . PREFIX . "inbox (id integer unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT, postid integer unsigned NOT NULL, postdate integer unsigned NOT NULL, poster varchar(50) NOT NULL, recipient varchar(50) NOT NULL, text varchar(20000) NOT NULL, INDEX(postid), INDEX(poster), INDEX(recipient)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;");
3819 }else{
3820 $db->exec('CREATE TABLE ' . PREFIX . "inbox (id $primary, postdate integer NOT NULL, postid integer NOT NULL, poster varchar(50) NOT NULL, recipient varchar(50) NOT NULL, text varchar(20000) NOT NULL);");
3821 $db->exec('CREATE INDEX ' . PREFIX . 'inbox_postid ON ' . PREFIX . 'inbox(postid);');
3822 $db->exec('CREATE INDEX ' . PREFIX . 'inbox_poster ON ' . PREFIX . 'inbox(poster);');
3823 $db->exec('CREATE INDEX ' . PREFIX . 'inbox_recipient ON ' . PREFIX . 'inbox(recipient);');
3824 }
3825 }
3826 if($dbversion<23){
3827 $db->exec('DELETE FROM ' . PREFIX . "settings WHERE setting='enablejs';");
3828 }
3829 if($dbversion<25){
3830 $db->exec('DELETE FROM ' . PREFIX . "settings WHERE setting='keeplimit';");
3831 }
3832 if($dbversion<26){
3833 $db->exec('INSERT INTO ' . PREFIX . 'settings (setting, value) VALUES (\'passregex\', \'.*\'), (\'nickregex\', \'^[A-Za-z0-9]*$\');');
3834 }
3835 if($dbversion<27){
3836 $db->exec('INSERT INTO ' . PREFIX . "settings (setting, value) VALUES ('externalcss', '');");
3837 }
3838 if($dbversion<28){
3839 $db->exec('INSERT INTO ' . PREFIX . "settings (setting, value) VALUES ('enablegreeting', '0');");
3840 }
3841 if($dbversion<29){
3842 $db->exec('INSERT INTO ' . PREFIX . "settings (setting, value) VALUES ('sortupdown', '0');");
3843 $db->exec('ALTER TABLE ' . PREFIX . 'members ADD COLUMN sortupdown smallint NOT NULL DEFAULT 0;');
3844 }
3845 if($dbversion<30){
3846 $db->exec('ALTER TABLE ' . PREFIX . 'filter ADD COLUMN cs smallint NOT NULL DEFAULT 0;');
3847 if(MEMCACHED){
3848 $memcached->delete(DBNAME . '-' . PREFIX . "filter");
3849 }
3850 }
3851 if($dbversion<31){
3852 $db->exec('INSERT INTO ' . PREFIX . "settings (setting, value) VALUES ('hidechatters', '0');");
3853 $db->exec('ALTER TABLE ' . PREFIX . 'members ADD COLUMN hidechatters smallint NOT NULL DEFAULT 0;');
3854 }
3855 if($dbversion<32 && DBDRIVER===0){
3856 //recreate db in utf8mb4
3857 try{
3858 $olddb=new PDO('mysql:host=' . DBHOST . ';dbname=' . DBNAME, DBUSER, DBPASS, [PDO::ATTR_ERRMODE=>PDO::ERRMODE_WARNING, PDO::ATTR_PERSISTENT=>PERSISTENT]);
3859 }catch(PDOException $e){
3860 send_fatal_error($I['nodb']);
3861 }
3862 $db->exec('DROP TABLE ' . PREFIX . 'captcha;');
3863 $db->exec('CREATE TABLE ' . PREFIX . "captcha (id integer PRIMARY KEY AUTO_INCREMENT, time integer NOT NULL, code char(5) NOT NULL) ENGINE=MEMORY DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;");
3864 $result=$olddb->query('SELECT filtermatch, filterreplace, allowinpm, regex, kick, cs FROM ' . PREFIX . 'filter;');
3865 $data=$result->fetchAll(PDO::FETCH_NUM);
3866 $db->exec('DROP TABLE ' . PREFIX . 'filter;');
3867 $db->exec('CREATE TABLE ' . PREFIX . "filter (id integer PRIMARY KEY AUTO_INCREMENT, filtermatch varchar(255) NOT NULL, filterreplace text NOT NULL, allowinpm smallint NOT NULL, regex smallint NOT NULL, kick smallint NOT NULL, cs smallint NOT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;");
3868 $stmt=$db->prepare('INSERT INTO ' . PREFIX . 'filter (filtermatch, filterreplace, allowinpm, regex, kick, cs) VALUES(?, ?, ?, ?, ?, ?);');
3869 foreach($data as $tmp){
3870 $stmt->execute($tmp);
3871 }
3872 $result=$olddb->query('SELECT ign, ignby FROM ' . PREFIX . 'ignored;');
3873 $data=$result->fetchAll(PDO::FETCH_NUM);
3874 $db->exec('DROP TABLE ' . PREFIX . 'ignored;');
3875 $db->exec('CREATE TABLE ' . PREFIX . "ignored (id integer PRIMARY KEY AUTO_INCREMENT, ign varchar(50) NOT NULL, ignby varchar(50) NOT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;");
3876 $stmt=$db->prepare('INSERT INTO ' . PREFIX . 'ignored (ign, ignby) VALUES(?, ?);');
3877 foreach($data as $tmp){
3878 $stmt->execute($tmp);
3879 }
3880 $db->exec('CREATE INDEX ' . PREFIX . 'ign ON ' . PREFIX . 'ignored(ign);');
3881 $db->exec('CREATE INDEX ' . PREFIX . 'ignby ON ' . PREFIX . 'ignored(ignby);');
3882 $result=$olddb->query('SELECT postdate, postid, poster, recipient, text FROM ' . PREFIX . 'inbox;');
3883 $data=$result->fetchAll(PDO::FETCH_NUM);
3884 $db->exec('DROP TABLE ' . PREFIX . 'inbox;');
3885 $db->exec('CREATE TABLE ' . PREFIX . "inbox (id integer PRIMARY KEY AUTO_INCREMENT, postdate integer NOT NULL, postid integer NOT NULL UNIQUE, poster varchar(50) NOT NULL, recipient varchar(50) NOT NULL, text text NOT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;");
3886 $stmt=$db->prepare('INSERT INTO ' . PREFIX . 'inbox (postdate, postid, poster, recipient, text) VALUES(?, ?, ?, ?, ?);');
3887 foreach($data as $tmp){
3888 $stmt->execute($tmp);
3889 }
3890 $db->exec('CREATE INDEX ' . PREFIX . 'inbox_poster ON ' . PREFIX . 'inbox(poster);');
3891 $db->exec('CREATE INDEX ' . PREFIX . 'inbox_recipient ON ' . PREFIX . 'inbox(recipient);');
3892 $result=$olddb->query('SELECT filtermatch, filterreplace, regex FROM ' . PREFIX . 'linkfilter;');
3893 $data=$result->fetchAll(PDO::FETCH_NUM);
3894 $db->exec('DROP TABLE ' . PREFIX . 'linkfilter;');
3895 $db->exec('CREATE TABLE ' . PREFIX . "linkfilter (id integer PRIMARY KEY AUTO_INCREMENT, filtermatch varchar(255) NOT NULL, filterreplace varchar(255) NOT NULL, regex smallint NOT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;");
3896 $stmt=$db->prepare('INSERT INTO ' . PREFIX . 'linkfilter (filtermatch, filterreplace, regex) VALUES(?, ?, ?);');
3897 foreach($data as $tmp){
3898 $stmt->execute($tmp);
3899 }
3900 $result=$olddb->query('SELECT nickname, passhash, status, refresh, bgcolour, regedby, lastlogin, timestamps, embed, incognito, style, nocache, tz, eninbox, sortupdown, hidechatters FROM ' . PREFIX . 'members;');
3901 $data=$result->fetchAll(PDO::FETCH_NUM);
3902 $db->exec('DROP TABLE ' . PREFIX . 'members;');
3903 $db->exec('CREATE TABLE ' . PREFIX . "members (id integer PRIMARY KEY AUTO_INCREMENT, nickname varchar(50) NOT NULL UNIQUE, passhash char(32) NOT NULL, status smallint NOT NULL, refresh smallint NOT NULL, bgcolour char(6) NOT NULL, regedby varchar(50) DEFAULT '', lastlogin integer DEFAULT 0, timestamps smallint NOT NULL, embed smallint NOT NULL, incognito smallint NOT NULL, style varchar(255) NOT NULL, nocache smallint NOT NULL, tz smallint NOT NULL, eninbox smallint NOT NULL, sortupdown smallint NOT NULL, hidechatters smallint NOT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;");
3904 $stmt=$db->prepare('INSERT INTO ' . PREFIX . 'members (nickname, passhash, status, refresh, bgcolour, regedby, lastlogin, timestamps, embed, incognito, style, nocache, tz, eninbox, sortupdown, hidechatters) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);');
3905 foreach($data as $tmp){
3906 $stmt->execute($tmp);
3907 }
3908 $result=$olddb->query('SELECT postdate, poststatus, poster, recipient, text, delstatus FROM ' . PREFIX . 'messages;');
3909 $data=$result->fetchAll(PDO::FETCH_NUM);
3910 $db->exec('DROP TABLE ' . PREFIX . 'messages;');
3911 $db->exec('CREATE TABLE ' . PREFIX . "messages (id integer PRIMARY KEY AUTO_INCREMENT, postdate integer NOT NULL, poststatus smallint NOT NULL, poster varchar(50) NOT NULL, recipient varchar(50) NOT NULL, text text NOT NULL, delstatus smallint NOT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;");
3912 $stmt=$db->prepare('INSERT INTO ' . PREFIX . 'messages (postdate, poststatus, poster, recipient, text, delstatus) VALUES(?, ?, ?, ?, ?, ?);');
3913 foreach($data as $tmp){
3914 $stmt->execute($tmp);
3915 }
3916 $db->exec('CREATE INDEX ' . PREFIX . 'poster ON ' . PREFIX . 'messages (poster);');
3917 $db->exec('CREATE INDEX ' . PREFIX . 'recipient ON ' . PREFIX . 'messages(recipient);');
3918 $db->exec('CREATE INDEX ' . PREFIX . 'postdate ON ' . PREFIX . 'messages(postdate);');
3919 $db->exec('CREATE INDEX ' . PREFIX . 'poststatus ON ' . PREFIX . 'messages(poststatus);');
3920 $result=$olddb->query('SELECT type, lastedited, editedby, text FROM ' . PREFIX . 'notes;');
3921 $data=$result->fetchAll(PDO::FETCH_NUM);
3922 $db->exec('DROP TABLE ' . PREFIX . 'notes;');
3923 $db->exec('CREATE TABLE ' . PREFIX . "notes (id integer PRIMARY KEY AUTO_INCREMENT, type char(5) NOT NULL, lastedited integer NOT NULL, editedby varchar(50) NOT NULL, text text NOT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;");
3924 $stmt=$db->prepare('INSERT INTO ' . PREFIX . 'notes (type, lastedited, editedby, text) VALUES(?, ?, ?, ?);');
3925 foreach($data as $tmp){
3926 $stmt->execute($tmp);
3927 }
3928 $result=$olddb->query('SELECT setting, value FROM ' . PREFIX . 'settings;');
3929 $data=$result->fetchAll(PDO::FETCH_NUM);
3930 $db->exec('DROP TABLE ' . PREFIX . 'settings;');
3931 $db->exec('CREATE TABLE ' . PREFIX . "settings (setting varchar(50) NOT NULL PRIMARY KEY, value text NOT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;");
3932 $stmt=$db->prepare('INSERT INTO ' . PREFIX . 'settings (setting, value) VALUES(?, ?);');
3933 foreach($data as $tmp){
3934 $stmt->execute($tmp);
3935 }
3936 }
3937 if($dbversion<33){
3938 $db->exec('CREATE TABLE ' . PREFIX . "files (id $primary, postid integer NOT NULL UNIQUE, filename varchar(255) NOT NULL, hash char(40) NOT NULL, type varchar(255) NOT NULL, data $longtext NOT NULL)$diskengine$charset;");
3939 $db->exec('CREATE INDEX ' . PREFIX . 'files_hash ON ' . PREFIX . 'files(hash);');
3940 $db->exec('INSERT INTO ' . PREFIX . "settings (setting, value) VALUES ('enfileupload', '0'), ('msgattache', '%2\$s [%1\$s]'), ('maxuploadsize', '1024');");
3941 }
3942 if($dbversion<34){
3943 $msg.="<br>$I[cssupdate]";
3944 $db->exec('ALTER TABLE ' . PREFIX . 'members ADD COLUMN nocache_old smallint NOT NULL DEFAULT 0;');
3945 }
3946 if($dbversion<37){
3947 $db->exec('ALTER TABLE ' . PREFIX . 'members MODIFY tz varchar(255) NOT NULL;');
3948 $db->exec('UPDATE ' . PREFIX . "members SET tz='UTC';");
3949 $db->exec('UPDATE ' . PREFIX . "settings SET value='UTC' WHERE setting='defaulttz';");
3950 }
3951 if($dbversion<38){
3952 $db->exec('INSERT INTO ' . PREFIX . "settings (setting, value) VALUES ('nextcron', '0');");
3953 $db->exec('DELETE FROM ' . PREFIX . 'inbox WHERE recipient NOT IN (SELECT nickname FROM ' . PREFIX . 'members);'); // delete inbox of members who deleted themselves
3954 }
3955 if($dbversion<39){
3956 $db->exec('INSERT INTO ' . PREFIX . "settings (setting, value) VALUES ('personalnotes', '1');");
3957 $result=$db->query('SELECT type, id FROM ' . PREFIX . 'notes;');
3958 while($tmp=$result->fetch(PDO::FETCH_NUM)){
3959 if($tmp[0]==='admin'){
3960 $tmp[0]=0;
3961 }else{
3962 $tmp[0]=1;
3963 }
3964 $data[]=$tmp;
3965 }
3966 $db->exec('ALTER TABLE ' . PREFIX . 'notes MODIFY type smallint NOT NULL;');
3967 $stmt=$db->prepare('UPDATE ' . PREFIX . 'notes SET type=? WHERE id=?;');
3968 foreach($data as $tmp){
3969 $stmt->execute($tmp);
3970 }
3971 $db->exec('CREATE INDEX ' . PREFIX . 'notes_type ON ' . PREFIX . 'notes(type);');
3972 $db->exec('CREATE INDEX ' . PREFIX . 'notes_editedby ON ' . PREFIX . 'notes(editedby);');
3973 }
3974 if($dbversion<41){
3975 $db->exec('DROP TABLE ' . PREFIX . 'sessions;');
3976 $db->exec('CREATE TABLE ' . PREFIX . "sessions (id $primary, session char(32) NOT NULL UNIQUE, nickname varchar(50) NOT NULL UNIQUE, status smallint NOT NULL, refresh smallint NOT NULL, style varchar(255) NOT NULL, lastpost integer NOT NULL, passhash varchar(255) NOT NULL, postid char(6) NOT NULL DEFAULT '000000', useragent varchar(255) NOT NULL, kickmessage varchar(255) DEFAULT '', bgcolour char(6) NOT NULL, entry integer NOT NULL, timestamps smallint NOT NULL, embed smallint NOT NULL, incognito smallint NOT NULL, ip varchar(45) NOT NULL, nocache smallint NOT NULL, tz varchar(255) NOT NULL, eninbox smallint NOT NULL, sortupdown smallint NOT NULL, hidechatters smallint NOT NULL, nocache_old smallint NOT NULL)$memengine$charset;");
3977 $db->exec('CREATE INDEX ' . PREFIX . 'status ON ' . PREFIX . 'sessions(status);');
3978 $db->exec('CREATE INDEX ' . PREFIX . 'lastpost ON ' . PREFIX . 'sessions(lastpost);');
3979 $db->exec('CREATE INDEX ' . PREFIX . 'incognito ON ' . PREFIX . 'sessions(incognito);');
3980 $result=$db->query('SELECT nickname, passhash, status, refresh, bgcolour, regedby, lastlogin, timestamps, embed, incognito, style, nocache, nocache_old, tz, eninbox, sortupdown, hidechatters FROM ' . PREFIX . 'members;');
3981 $members=$result->fetchAll(PDO::FETCH_NUM);
3982 $result=$db->query('SELECT postdate, postid, poster, recipient, text FROM ' . PREFIX . 'inbox;');
3983 $inbox=$result->fetchAll(PDO::FETCH_NUM);
3984 $db->exec('DROP TABLE ' . PREFIX . 'inbox;');
3985 $db->exec('DROP TABLE ' . PREFIX . 'members;');
3986 $db->exec('CREATE TABLE ' . PREFIX . "members (id $primary, nickname varchar(50) NOT NULL UNIQUE, passhash varchar(255) NOT NULL, status smallint NOT NULL, refresh smallint NOT NULL, bgcolour char(6) NOT NULL, regedby varchar(50) DEFAULT '', lastlogin integer DEFAULT 0, timestamps smallint NOT NULL, embed smallint NOT NULL, incognito smallint NOT NULL, style varchar(255) NOT NULL, nocache smallint NOT NULL, nocache_old smallint NOT NULL, tz varchar(255) NOT NULL, eninbox smallint NOT NULL, sortupdown smallint NOT NULL, hidechatters smallint NOT NULL)$diskengine$charset");
3987 $stmt=$db->prepare('INSERT INTO ' . PREFIX . 'members (nickname, passhash, status, refresh, bgcolour, regedby, lastlogin, timestamps, embed, incognito, style, nocache, nocache_old, tz, eninbox, sortupdown, hidechatters) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);');
3988 foreach($members as $tmp){
3989 $stmt->execute($tmp);
3990 }
3991 $db->exec('CREATE TABLE ' . PREFIX . "inbox (id $primary, postdate integer NOT NULL, postid integer NOT NULL UNIQUE, poster varchar(50) NOT NULL, recipient varchar(50) NOT NULL, text text NOT NULL)$diskengine$charset;");
3992 $stmt=$db->prepare('INSERT INTO ' . PREFIX . 'inbox (postdate, postid, poster, recipient, text) VALUES(?, ?, ?, ?, ?);');
3993 foreach($inbox as $tmp){
3994 $stmt->execute($tmp);
3995 }
3996 $db->exec('CREATE INDEX ' . PREFIX . 'inbox_poster ON ' . PREFIX . 'inbox(poster);');
3997 $db->exec('CREATE INDEX ' . PREFIX . 'inbox_recipient ON ' . PREFIX . 'inbox(recipient);');
3998 $db->exec('ALTER TABLE ' . PREFIX . 'inbox ADD FOREIGN KEY (recipient) REFERENCES ' . PREFIX . 'members(nickname) ON DELETE CASCADE ON UPDATE CASCADE;');
3999 }
4000 if($dbversion<42){
4001 $db->exec('INSERT IGNORE INTO ' . PREFIX . "settings (setting, value) VALUES ('filtermodkick', '1');");
4002 }
4003 update_setting('dbversion', DBVERSION);
4004 if($msgencrypted!==MSGENCRYPTED){
4005 if(!extension_loaded('openssl')){
4006 send_fatal_error($I['opensslextrequired']);
4007 }
4008 $result=$db->query('SELECT id, text FROM ' . PREFIX . 'messages;');
4009 $stmt=$db->prepare('UPDATE ' . PREFIX . 'messages SET text=? WHERE id=?;');
4010 while($message=$result->fetch(PDO::FETCH_ASSOC)){
4011 if(MSGENCRYPTED){
4012 $message['text']=openssl_encrypt($message['text'], 'aes-256-cbc', ENCRYPTKEY, 0, '1234567890123456');
4013 }else{
4014 $message['text']=openssl_decrypt($message['text'], 'aes-256-cbc', ENCRYPTKEY, 0, '1234567890123456');
4015 }
4016 $stmt->execute([$message['text'], $message['id']]);
4017 }
4018 $result=$db->query('SELECT id, text FROM ' . PREFIX . 'notes;');
4019 $stmt=$db->prepare('UPDATE ' . PREFIX . 'notes SET text=? WHERE id=?;');
4020 while($message=$result->fetch(PDO::FETCH_ASSOC)){
4021 if(MSGENCRYPTED){
4022 $message['text']=openssl_encrypt($message['text'], 'aes-256-cbc', ENCRYPTKEY, 0, '1234567890123456');
4023 }else{
4024 $message['text']=openssl_decrypt($message['text'], 'aes-256-cbc', ENCRYPTKEY, 0, '1234567890123456');
4025 }
4026 $stmt->execute([$message['text'], $message['id']]);
4027 }
4028 update_setting('msgencrypted', (int) MSGENCRYPTED);
4029 }
4030 send_update($msg);
4031}
4032
4033function get_setting($setting){
4034 global $db, $memcached;
4035 if(!MEMCACHED || !$value=$memcached->get(DBNAME . '-' . PREFIX . "settings-$setting")){
4036 $stmt=$db->prepare('SELECT value FROM ' . PREFIX . 'settings WHERE setting=?;');
4037 $stmt->execute([$setting]);
4038 $stmt->bindColumn(1, $value);
4039 $stmt->fetch(PDO::FETCH_BOUND);
4040 if(MEMCACHED){
4041 $memcached->set(DBNAME . '-' . PREFIX . "settings-$setting", $value);
4042 }
4043 }
4044 return $value;
4045}
4046
4047function update_setting($setting, $value){
4048 global $db, $memcached;
4049 $stmt=$db->prepare('UPDATE ' . PREFIX . 'settings SET value=? WHERE setting=?;');
4050 $stmt->execute([$value, $setting]);
4051 if(MEMCACHED){
4052 $memcached->set(DBNAME . '-' . PREFIX . "settings-$setting", $value);
4053 }
4054}
4055
4056// configuration, defaults and internals
4057
4058function check_db(){
4059 global $I, $db, $memcached;
4060 $options=[PDO::ATTR_ERRMODE=>PDO::ERRMODE_WARNING, PDO::ATTR_PERSISTENT=>PERSISTENT];
4061 try{
4062 if(DBDRIVER===0){
4063 if(!extension_loaded('pdo_mysql')){
4064 send_fatal_error($I['pdo_mysqlextrequired']);
4065 }
4066 $db=new PDO('mysql:host=' . DBHOST . ';dbname=' . DBNAME . ';charset=utf8mb4', DBUSER, DBPASS, $options);
4067 }elseif(DBDRIVER===1){
4068 if(!extension_loaded('pdo_pgsql')){
4069 send_fatal_error($I['pdo_pgsqlextrequired']);
4070 }
4071 $db=new PDO('pgsql:host=' . DBHOST . ';dbname=' . DBNAME, DBUSER, DBPASS, $options);
4072 }else{
4073 if(!extension_loaded('pdo_sqlite')){
4074 send_fatal_error($I['pdo_sqliteextrequired']);
4075 }
4076 $db=new PDO('sqlite:' . SQLITEDBFILE, NULL, NULL, $options);
4077 }
4078 }catch(PDOException $e){
4079 try{
4080 //Attempt to create database
4081 if(DBDRIVER===0){
4082 $db=new PDO('mysql:host=' . DBHOST, DBUSER, DBPASS, $options);
4083 if(false!==$db->exec('CREATE DATABASE ' . DBNAME)){
4084 $db=new PDO('mysql:host=' . DBHOST . ';dbname=' . DBNAME . ';charset=utf8mb4', DBUSER, DBPASS, $options);
4085 }else{
4086 send_fatal_error($I['nodbsetup']);
4087 }
4088
4089 }elseif(DBDRIVER===1){
4090 $db=new PDO('pgsql:host=' . DBHOST, DBUSER, DBPASS, $options);
4091 if(false!==$db->exec('CREATE DATABASE ' . DBNAME)){
4092 $db=new PDO('pgsql:host=' . DBHOST . ';dbname=' . DBNAME, DBUSER, DBPASS, $options);
4093 }else{
4094 send_fatal_error($I['nodbsetup']);
4095 }
4096 }else{
4097 if(isset($_REQUEST['action']) && $_REQUEST['action']==='setup'){
4098 send_fatal_error($I['nodbsetup']);
4099 }else{
4100 send_fatal_error($I['nodb']);
4101 }
4102 }
4103 }catch(PDOException $e){
4104 if(isset($_REQUEST['action']) && $_REQUEST['action']==='setup'){
4105 send_fatal_error($I['nodbsetup']);
4106 }else{
4107 send_fatal_error($I['nodb']);
4108 }
4109 }
4110 }
4111 if(MEMCACHED){
4112 if(!extension_loaded('memcached')){
4113 send_fatal_error($I['memcachedextrequired']);
4114 }
4115 $memcached=new Memcached();
4116 $memcached->addServer(MEMCACHEDHOST, MEMCACHEDPORT);
4117 }
4118 if(!isset($_REQUEST['action']) || $_REQUEST['action']==='setup'){
4119 if(!check_init()){
4120 send_init();
4121 }
4122 update_db();
4123 }elseif($_REQUEST['action']==='init'){
4124 init_chat();
4125 }
4126}
4127
4128function load_fonts(){
4129 return [
4130 'Arial' =>"font-family:'Arial','Helvetica','sans-serif';",
4131 'Book Antiqua' =>"font-family:'Book Antiqua','MS Gothic';",
4132 'Comic' =>"font-family:'Comic Sans MS','Papyrus';",
4133 'Courier' =>"font-family:'Courier New','Courier','monospace';",
4134 'Cursive' =>"font-family:'Cursive','Papyrus';",
4135 'Fantasy' =>"font-family:'Fantasy','Futura','Papyrus';",
4136 'Garamond' =>"font-family:'Garamond','Palatino','serif';",
4137 'Georgia' =>"font-family:'Georgia','Times New Roman','Times','serif';",
4138 'Serif' =>"font-family:'MS Serif','New York','serif';",
4139 'System' =>"font-family:'System','Chicago','sans-serif';",
4140 'Times New Roman' =>"font-family:'Times New Roman','Times','serif';",
4141 'Verdana' =>"font-family:'Verdana','Geneva','Arial','Helvetica','sans-serif';",
4142 ];
4143}
4144
4145function load_lang(){
4146 global $I, $L, $language;
4147 $L=[
4148 'bg' =>'Български',
4149 'cz' =>'čeština',
4150 'de' =>'Deutsch',
4151 'en' =>'English',
4152 'es' =>'Español',
4153 'fr' =>'Français',
4154 'id' =>'Bahasa Indonesia',
4155 'it' =>'Italiano',
4156 'ru' =>'Русский',
4157 'uk' =>'Українська',
4158 'zh_CN' =>'简体中文',
4159 ];
4160 if(isset($_REQUEST['lang']) && isset($L[$_REQUEST['lang']])){
4161 $language=$_REQUEST['lang'];
4162 if(!isset($_COOKIE['language']) || $_COOKIE['language']!==$language){
4163 setcookie('language', $language);
4164 }
4165 }elseif(isset($_COOKIE['language']) && isset($L[$_COOKIE['language']])){
4166 $language=$_COOKIE['language'];
4167 }else{
4168 $language=LANG;
4169 setcookie('language', $language);
4170 }
4171 include('lang_en.php'); //always include English
4172 if($language!=='en'){
4173 $T=[];
4174 include("lang_$language.php"); //replace with translation if available
4175 foreach($T as $name=>$translation){
4176 $I[$name]=$translation;
4177 }
4178 }
4179}
4180
4181function load_config(){
4182 mb_internal_encoding('UTF-8');
4183 define('VERSION', '1.23.6'); // Script version
4184 define('DBVERSION', 41); // Database layout version
4185 define('MSGENCRYPTED', true); // Store messages encrypted in the database to prevent other database users from reading them - true/false - visit the setup page after editing!
4186 define('ENCRYPTKEY', ''); // Encryption key for messages
4187 define('DBHOST', 'localhost'); // Database host
4188 define('DBUSER', ''); // Database user
4189 define('DBPASS', ''); // Database password
4190 define('DBNAME', ''); // Database
4191 define('PERSISTENT', true); // Use persistent database conection true/false
4192 define('PREFIX', '1'); // Prefix - Set this to a unique value for every chat, if you have more than 1 chats on the same database or domain - use only alpha-numeric values (A-Z, a-z, 0-9, or _) other symbols might break the queries
4193 define('MEMCACHED', false); // Enable/disable memcached caching true/false - needs memcached extension and a memcached server.
4194 if(MEMCACHED){
4195 define('MEMCACHEDHOST', 'localhost'); // Memcached host
4196 define('MEMCACHEDPORT', '11211'); // Memcached port
4197 }
4198 define('DBDRIVER', 0); // Selects the database driver to use - 0=MySQL, 1=PostgreSQL, 2=sqlite
4199 if(DBDRIVER===2){
4200 define('SQLITEDBFILE', 'public_chat.sqlite'); // Filepath of the sqlite database, if sqlite is used - make sure it is writable for the webserver user
4201 }
4202 define('COOKIENAME', PREFIX . 'chat_session'); // Cookie name storing the session information
4203 define('LANG', 'en'); // Default language
4204}