query('SELECT thread, msgid, author FROM rss ORDER BY msgid DESC, thread DESC LIMIT 100;'); if (! $sqlres) { echo "SQL ERROR: QUERY FAILED\n"; return false; } header('content-type: application/rss+xml'); echo '' . "\n"; echo '' . "\n"; echo "\n"; echo "" . htmlspecialchars($RSS_TITLE, ENT_XML1) . "\n"; echo "" . selfurl(). "\n"; while ($row = $sqlres->fetchArray()) { $rawtitle = file_get_contents($DATADIR . 'threads/' . $row['thread'] . '/title.txt'); if (empty($rawtitle)) continue; $title = htmlspecialchars($rawtitle, ENT_XML1, 'UTF-8'); $author = htmlspecialchars($row['author'], ENT_XML1, 'UTF-8'); if ($NICE_URLS) { $link = selfurl(); if (substr($link, -1) !== '/') $link .= '/'; $link .= "{$row['thread']}"; } else { $link = selfurl('thread=' . $row['thread']); } $link .= '#' . $row['msgid']; echo "\n"; echo "{$author} @ '{$title}'\n"; echo "" . htmlspecialchars($link, ENT_XML1) . "\n"; echo "{$author} @ '{$title}'\n"; echo "" . date('r', $row['msgid']) . "\n"; echo "" . htmlspecialchars($link, ENT_XML1) . "\n"; echo "\n"; } $db->close(); echo "\n"; echo "\n"; return true; } function formularz($thread = 0, $postid = 0, $msg = '') { global $STR; global $LANG; global $NICE_URLS; if ($thread == 0) { echo '
' . "\n"; echo '' . "\n"; } else { echo '' . "\n"; echo '' . "\n"; if ($postid > 0) { echo '' . "\n"; echo '' . "\n"; } else { echo '' . "\n"; } } echo '
' . "\n"; echo '

' . $STR[$LANG]['nameornick'] . '

' . $STR[$LANG]['password'] . ' (' . $STR[$LANG]['optional'] . ')

' . "\n"; if ($thread == 0) { echo '
' . "\n"; echo "

" . $STR[$LANG]['threadsubj'] . "

\n"; echo '' . "\n"; echo "
\n"; } echo '
\n"; echo "
\n"; // --- CAPTCHA --- $capid = rand(1, 5); echo '
' . $STR[$LANG]['captcha'][$capid] . ': ' . "\n"; echo ''; // --------------- echo '
' . "\n"; $link = selfurl(); if ($postid > 0) { $link = selfurl("thread=" . $thread); if ($NICE_URLS) $link = $thread; $link .= '#' . $postid; } echo '' . $STR[$LANG]['cancel'] . ' ' . "\n"; echo "
\n"; echo "
\n"; echo '
'; } function wyswietl_watek_w_liscie($threadid, $tytul, $lastauthor, $lastupdate) { global $NICE_URLS; global $STR; global $LANG; echo '' . "\n"; echo '

' . htmlspecialchars($tytul) . "

\n"; echo '

' . $STR[$LANG]['latestentry'] . ' ' . htmlspecialchars($lastauthor) . ', ' . htmlspecialchars(data_dluga($lastupdate)) . "

\n"; echo "
\n"; } function sprawdz_captcha($CAPARR) { //echo "\n"; switch ($CAPARR['capid']) { case 1: if (($CAPARR['c1']) && (!$CAPARR['c2']) && (!$CAPARR['c3'])) return(true); break; case 2: if ((!$CAPARR['c1']) && ($CAPARR['c2']) && (!$CAPARR['c3'])) return(true); break; case 3: if ((!$CAPARR['c1']) && (!$CAPARR['c2']) && ($CAPARR['c3'])) return(true); break; case 4: if (($CAPARR['c1']) && (!$CAPARR['c2']) && ($CAPARR['c3'])) return(true); break; case 5: if ((!$CAPARR['c1']) && ($CAPARR['c2']) && ($CAPARR['c3'])) return(true); break; } return(false); } // zwraca akcję na podstawie globalnych POST lub GET function getvar_action() { if (!empty($_POST['action'])) return $_POST['action']; if (!empty($_GET['action'])) return $_GET['action']; return(''); } function getvar_thread() { if (!empty($_POST['thread'])) return intval($_POST['thread']); if (!empty($_GET['thread'])) return intval($_GET['thread']); return(-1); } function getvar_archiveyear() { if (!empty($_POST['arch'])) return intval($_POST['arch']); if (!empty($_GET['arch'])) return intval($_GET['arch']); return(-1); } // funkcja która zapisuje nowe wiadomości function mateuszbb_preprocess() { global $TRIP_SALT; global $DATADIR; global $NICE_URLS; global $ERRSTR; // zmienna zawierająca komunikat błędu (jeśli jakiś wystąpił) global $STR; global $LANG; global $MAXDAILYPOSTS; global $EDIT_ALLOWED_MINUTES; $action = getvar_action(); $thread = getvar_thread(); $archiveyear = getvar_archiveyear(); // negotiate language, unless forced by configuration if (empty($LANG)) { $LANG = 'en'; // preselect english as default language foreach (getpreflang() as $l) { if (!empty($STR[$l])) { $LANG = $l; break; } } } else { // if language forced by configuration then make sure it is supported if (empty($STR[$LANG])) $LANG = 'en'; // fall back to 'en' on error } // write access: check how many messages the user posted during last 24h if (($action === 'createthread') || ($action === 'newpost')) { $db = new SQLite3($DATADIR . 'mateuszbb.sqlite3'); if ($db) { $db->exec('DELETE FROM ip_msg_counters24h WHERE msgid < strftime(\'%s\', \'now\') - 24*3600;'); $count24h = intval($db->querySingle("SELECT count(*) FROM ip_msg_counters24h WHERE ipaddr = '{$_SERVER['REMOTE_ADDR']}'")); $db->close(); if ($count24h >= $MAXDAILYPOSTS) { $ERRSTR = "BŁĄD: Z TWOJEGO ADRESU NAPISANO JUŻ {$count24h} WIADOMOŚCI W PRZECIĄGU OSTATNICH 24H. SPRÓBUJ PONOWNIE ZA JAKIŚ CZAS."; $action = ''; } } } // edit post becomes newpost, it was different just to avoid 24h counters if ($action === 'editpost') $action = 'newpost'; // new thread creation (+switch to read thread) if ($action === 'createthread') { // captcha check if (!sprawdz_captcha($_POST)) { echo "

BŁĄD: NIEPRAWIDŁOWE CAPTCHA

\n"; goto DONE; } // $thread = time(); if (empty($_POST['username']) || (empty($_POST['msg'])) || (empty($_POST['title']))) { echo '

BŁĄD: pusty nick, wiadomość lub tytuł

' . "\n"; goto DONE; } if (!mkdir($DATADIR . 'threads/' . $thread, 0755, true)) { echo '

BŁĄD: nie zdołano utworzyć wątku nr ' . $thread . "

\n"; goto DONE; } // zapisz tytuł file_put_contents($DATADIR . 'threads/' . $thread . '/title.txt', trim($_POST['title'])); // ustaw co trzeba żeby zapisać wiadomość $action = 'newpost'; } // nowy post do istniejącego wątku if (($action === 'newpost') && ($thread >= 0) && (!empty($_POST['msg'])) && (!empty($_POST['username']))) { // is it really about a NEW post or about EDITING an existing one? if (empty($_POST['postid'])) { $postid = time(); } else { // editing an existing post $msg = loadmsg($_POST['thread'], $_POST['postid']); if (!is_art_edition_allowed($_POST['postid'], $msg)) { $action = ''; $ERRSTR = "NOT ALLOWED"; goto DONE; } $postid = $_POST['postid']; } if (!sprawdz_captcha($_POST)) { $ERRSTR = "BŁĄD: NIEPRAWIDŁOWE CAPTCHA"; goto DONE; } // nadpisz lastauthor i lastupdate $lastupdate = array('lastupdate' => $postid, 'lastauthor' => trim($_POST['username'])); file_put_contents($DATADIR . 'threads/' . $thread . '/lastupdate', serialize($lastupdate)); // oblicz tripkod, jeśli hasło zostało ustawione $tripsig = ''; if (!empty(trim($_POST['password']))) { $tripsig = hash('whirlpool', trim($_POST['username']) . '#' . trim($_POST['password']) . $TRIP_SALT); } // wygeneruj klucz do edycji postu i prześlij go przeglądarce przez ciasteczko (chyba że przeglądarka już ma klucz) if (!empty($EDIT_ALLOWED_MINUTES)) { if (!empty($_COOKIE['mateuszbbkey'])) { $artkey = $_COOKIE['mateuszbbkey']; } else { $artkey = bin2hex(random_bytes(128)); setcookie('mateuszbbkey', $artkey, array('secure' => true, 'httponly' => true, 'samesite' => 'Lax')); } } // zapisz wiadomość $msg = array('author' => trim($_POST['username']), 'ip' => $_SERVER['REMOTE_ADDR'], 'trip' => $tripsig, 'msg' => trim($_POST['msg']), 'key' => password_hash($artkey, PASSWORD_DEFAULT)); file_put_contents($DATADIR . 'threads/' . $thread . '/' . $postid, serialize($msg)); // zaktualizuj metadane dot. ostatniego wpisu, ostatniego autora i ilości wpisów dla tego IP w ciągu ostatniej godziny, ale tylko dla nowych wpisów (nie dla edycji) if (empty($_POST['postid'])) { $db = new SQLite3($DATADIR . 'mateuszbb.sqlite3'); if ($db) { $db->exec('CREATE TABLE IF NOT EXISTS newest (thread INTEGER PRIMARY KEY, lastupdate INTEGER NOT NULL, lastauthor TEXT NOT NULL);'); $db->exec('CREATE INDEX IF NOT EXISTS lastupdated ON newest (lastupdate);'); $db->exec('CREATE TABLE IF NOT EXISTS ip_msg_counters24h (threadid INTEGER NOT NULL, msgid INTEGER NOT NULL, ipaddr TEXT NOT NULL);'); $db->exec('CREATE TABLE IF NOT EXISTS rss (thread INTEGER NOT NULL, msgid INTEGER NOT NULL, author TEXT NOT NULL);'); $db->exec('CREATE INDEX IF NOT EXISTS rss_msgid ON rss (msgid);'); $login_escaped = $db->escapeString(trim($_POST['username'])); $db->exec("INSERT OR REPLACE INTO newest (thread, lastupdate, lastauthor) VALUES ({$thread}, {$postid}, '{$login_escaped}');"); $db->exec("INSERT INTO rss (thread, msgid, author) VALUES ({$thread}, {$postid}, '{$login_escaped}');"); $db->exec("INSERT INTO ip_msg_counters24h (threadid, msgid, ipaddr) VALUES ({$thread}, {$postid}, '{$_SERVER['REMOTE_ADDR']}');"); $db->close(); } else { echo "SQL ERROR WHILE WRITING STATS\n"; } } // przekieruj if ($NICE_URLS) { $newurl = "{$thread}#{$postid}"; } else { $newurl = selfurl("thread={$thread}") . "#{$postid}"; } header("Location: {$newurl}"); echo "KLIKNIJ TUTAJ\n"; exit(); } DONE: } function mateuszbb_tytulwatku($id) { global $DATADIR; return file_get_contents($DATADIR . 'threads/' . $id . '/title.txt'); } // returns an array of last n threads with most recent activity that had activity // in last maxinact days. returns false on error or empty set. // the returned result, when not false, is an array of arrays, where each // leaf array represents one thread function mateuszbb_getactivethreads($n, $maxinact = -1) { global $DATADIR; $result = array(); $db = new SQLite3($DATADIR . 'mateuszbb.sqlite3', SQLITE3_OPEN_READONLY); if (! $db) return(false); $minupdatedate = 0; if ($maxinact >= 0) $minupdatedate = time() - (intval($maxinact) * 86400); $sqlquery = 'SELECT thread, lastupdate, lastauthor FROM newest WHERE lastupdate > ' . $minupdatedate . ' ORDER BY lastupdate DESC LIMIT ' . intval($n) . ';'; $sqlres = $db->query($sqlquery); if (! $sqlres) { $db->close(); return(false); } // kopiuj wpisy do nowej tablicy while ($row = $sqlres->fetchArray()) { $result[] = $row; } $db->close(); return($result); } // returns true if post can be edited by current user function is_art_edition_allowed($timestamp, $msg) { global $EDIT_ALLOWED_MINUTES; if ($EDIT_ALLOWED_MINUTES >= 0) { if (((time() - $timestamp) / 60) >= $EDIT_ALLOWED_MINUTES) return(false); // only posts from last x minutes can be edited } if (empty($_COOKIE['mateuszbbkey'])) return(false); if (empty($msg['key'])) return(false); return(password_verify($_COOKIE['mateuszbbkey'], $msg['key'])); } function loadmsg($threadid, $postid) { global $DATADIR; $fname = $DATADIR . 'threads/' . $threadid . '/' . $postid; if (!file_exists($fname)) return(false); return(unserialize(file_get_contents($fname))); } // wyświetlanie UI itd function mateuszbb_start() { global $TRIP_SALT; global $ERRSTR; global $DATADIR; global $INITYEAR; global $LANG; global $STR; global $NICE_URLS; global $SEARCH_API_URL; global $TZ; global $LOCK_DELAY; global $MAINPAGE_MAXTHREADS; global $MAINPAGE_MAXINACT; // read global variables $action = getvar_action(); $thread = getvar_thread(); $archiveyear = getvar_archiveyear(); // ustaw strefę czasową, jeśli jakaś jest skonfigurowana if (!empty($TZ)) date_default_timezone_set($TZ); // wyświetl błąd, jeśli jakiś wystąpił w mateuszbb_preprocess() if (!empty($ERRSTR)) { echo "

{$ERRSTR}

\n"; $action = ''; echo '

Wróć do głównej strony

' . "\n"; goto DONE; } // szukanie if (isset($_POST['szukaj']) && (!empty(trim($_POST['szukaj'])))) { $q = trim($_POST['szukaj']); $query = $SEARCH_API_URL . urlencode($q); echo '

' . $STR[$LANG]['searchterm'] . ' ' . htmlentities($q) . '

'; $results = file_get_contents($query); $resarr = json_decode($results, true)['items']; $licznik = 0; foreach ($resarr as $r) { if (mb_substr($r['link'], -1) === '/') continue; echo ''; echo "

{$r['title']}

{$r['htmlSnippet']}

\n"; $licznik++; } if ($licznik == 0) echo "

" . $STR[$LANG]['noresults'] . "

\n"; goto DONE; } // edit post if ($action === 'editpostform') { $msg = loadmsg($_POST['thread'], $_POST['post']); if (is_art_edition_allowed($_POST['post'], $msg)) { formularz(intval($_POST['thread']), intval($_POST['post']), $msg); } else { echo "

Link expired

\n"; } GOTO DONE; } // new thread form if ($action === 'newthread') { echo '

' . $STR[$LANG]['newthread'] . '

' . "\n"; formularz(); goto DONE; } // zobacz listę wątków (main page) if ((empty($action)) && ($thread < 0) && ($archiveyear <= 0)) { // display the main page header if any is defined if (file_exists($DATADIR . 'mateuszbb-main-head.html')) { readfile($DATADIR . 'mateuszbb-main-head.html'); } // list wątków echo '
'; echo '
'; echo '' . $STR[$LANG]['opnewthread'] . ''; echo "
\n"; $lista_watkow = mateuszbb_getactivethreads($MAINPAGE_MAXTHREADS, $MAINPAGE_MAXINACT); if ($lista_watkow === false) { echo "

NO ENTRIES FOUND

"; } else { foreach ($lista_watkow as $row) { $title = mateuszbb_tytulwatku($row['thread']); if (empty($title)) { echo "\n"; continue; } wyswietl_watek_w_liscie($row['thread'], $title, $row['lastauthor'], $row['lastupdate']); } } echo '
' . "\n"; echo '
' . $STR[$LANG]['archives'] . ':'; for ($y = $INITYEAR; $y <= intval(gmdate('Y')); $y++) { if ($NICE_URLS) { echo " {$y}"; } else { echo ' ' . $y . ''; } } echo "
\n"; echo 'RSS' . "\n"; echo "
\n"; // display the main page footer if any is defined if (file_exists($DATADIR . 'mateuszbb-main-foot.html')) { readfile($DATADIR . 'mateuszbb-main-foot.html'); } goto DONE; } // wyświetl archiwum if ($archiveyear > 0) { echo '
' . $STR[$LANG]['backtocur'] . '
' . "\n"; echo '

' . $STR[$LANG]['archives'] . " {$archiveyear}

\n"; $threads = scandir($DATADIR . 'threads/', SCANDIR_SORT_ASCENDING); foreach ($threads as $t) { if (!preg_match('/^[0-9][0-9]*$/', $t)) continue; // skip anything that is not a thread id if (intval(gmdate('Y', $t)) != $archiveyear) continue; // skip threads out of the targeted year $title = file_get_contents($DATADIR . 'threads/' . $t . '/title.txt'); $link = $t; if (! $NICE_URLS) $link = selfurl("thread={$t}"); echo '[' . gmdate("Y-m-d", $t) . "] {$title}
\n"; } goto DONE; } // zobacz wątek if ((empty($action)) && ($thread >= 0)) { // załaduj listę postów (i zapamiętaj ostatnią pozycję) $listapostow = scandir($DATADIR . 'threads/' . $thread . '/'); // usuń pozycje które nie są żadnym msgid (np. title.txt) i zapamiętaj ostatni msgid $posty = array(); foreach ($listapostow as $p) { if (!preg_match('/^[0-9][0-9]*$/', $p)) continue; // skip anything that is not a messageid $posty[] = $p; $ostatnipost = $p; } // is this thread locked? $islocked = false; if (($LOCK_DELAY >= 0) && ((time() - intval($ostatnipost)) / 86400 >= $LOCK_DELAY)) $islocked = true; // toolbar (ostatni wątek / odpowiedz / powrót do forum) echo '
'; echo '' . $STR[$LANG]['jumptoend'] . ''; if (! $islocked) echo ' ' . $STR[$LANG]['reply'] . ''; echo ' ' . $STR[$LANG]['listthreads'] . '
' . "\n"; // wyświetl tytuł wątku echo '

' . htmlspecialchars(file_get_contents($DATADIR . 'threads/' . $thread . '/title.txt')) . "

\n"; // "thread is locked" if ($islocked) echo '

' . $STR[$LANG]['locked'] . "

\n"; // wyświetl listę postów foreach ($posty as $p) { $msg = loadmsg($thread, $p); echo '
' . "\n"; echo '
\n"; if (!empty($msg['trip'])) { echo '
'; echo chunk_split($msg['trip'], 16, "\n"); echo "
\n"; } echo "
\n"; // symbole html $bodyprocessed = htmlspecialchars($msg['msg']); // ludzie czasem dodają znaczniki [img] do obrazków, usuń je (ale tylko jeśli są na początku linii) $bodyprocessed = preg_replace('~^(\[img\])(.*)(\[/img\])~m', '$2', $bodyprocessed); // dodaj podgląd pod linki do obrazków, ale tylko jeśli link jest sam w linijce $bodyprocessed = preg_replace('~^(http[s]?://[^<>[:space:]]+[[:alnum:]/]\.(jpg|png))($|[\r\n]{1,2})~m', "$1\n\n", $bodyprocessed); // olinkuj linki $bodyprocessed = preg_replace("~([^\"]|^)(http[s]?://[^<>[:space:]]+[[:alnum:]/=])~", "$1$2", $bodyprocessed); // oflaguj cytaty (linijki zaczynające się od ">") $bodyprocessed = preg_replace('/^(>.*)[\r]?\n/m', '
$1
', $bodyprocessed); echo '
'; // czy mogę edytować? if (is_art_edition_allowed($p, $msg)) { echo '
'; } echo $bodyprocessed . "
\n"; echo "
\n"; } // formularz odpowiedzi albo komunikat o zamknięciu if ($islocked) { echo '

' . $STR[$LANG]['locked'] . "

\n"; } else { formularz($thread); } goto DONE; } DONE: } ?>