960 lines
32 KiB
PHP
960 lines
32 KiB
PHP
<?php
|
|
|
|
/*
|
|
* This is the endboard software, version beta 0.80.
|
|
* It is a textboard, written for the use in the darknets.
|
|
*
|
|
* This file contains all the functions needed for the second page, located
|
|
* under /srv/endboard/mob by default. This page is meant for mobile phones
|
|
* and other devices with touchscreens. It is sourced by the index file in
|
|
* that directory.
|
|
*
|
|
* The writing of this code started some time ago with another software
|
|
* called smolBBS. Although there is almost no original code left now,
|
|
* I still regard endboard as a fork of smolBBS.
|
|
* The author of smolBBS has required that the following text be
|
|
* distributed with any redistribution, so here it goes.
|
|
* The license and other conditions apply to endboard as well.
|
|
*
|
|
* IRC: *dulm @ irc.rizon.net
|
|
*
|
|
* Copyright (C) 2020 sandlind
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are
|
|
* met:
|
|
*
|
|
* (1) Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
*
|
|
* (2) Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in
|
|
* the documentation and/or other materials provided with the
|
|
* distribution.
|
|
*
|
|
* (3)The name of the author may not be used to
|
|
* endorse or promote products derived from this software without
|
|
* specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
|
|
// Give a new location to the browser.
|
|
// Does not work with lynx, unfortunately, but then the link can be used.
|
|
// For the mobile version, lynx does not matter, of course.
|
|
function answer_redirect_mob($sub)
|
|
{
|
|
|
|
header( "refresh:3;url=/mob/s/$sub" );
|
|
// we wait 3 seconds with the redirection
|
|
$html_string = '<title>wait for it...</title></head>'
|
|
. '<body><div class="site-container">'
|
|
. '<div class="posts" id="posts">'
|
|
. '<div class="message first">'
|
|
. '<h3>Redirection in about 3 secs.'
|
|
. ' If that does not work, go'
|
|
. " <a href='/mob/s/$sub'>back</a>.</div></div>";
|
|
|
|
echo "$html_string";
|
|
}
|
|
|
|
// Translate simple bbcode to html, and highlight quotes, like so:
|
|
// [b bold],[i italic],[u underlined],[s strikethrough]
|
|
// [h headline],[sp spoiler],[li list element],[url link],>>quote\r\n
|
|
function bbcode_to_html_mob($text, $settings)
|
|
{
|
|
if ( ($settings['enable_bbcode'] == FALSE) ) {
|
|
return $text;
|
|
}
|
|
|
|
$search = array (
|
|
'/(\[b\ )(.*)(\])/',
|
|
'/(\[i\ )(.*)(\])/',
|
|
'/(\[u\ )(.*)(\])/',
|
|
'/(\[s\ )(.*)(\])/',
|
|
'/(\[h\ )(.*)(\])/',
|
|
'/(\[sp\ )(.*)(\])/',
|
|
'/(\[li\ )(.*)(\])/',
|
|
'/(\[url\ )(.*)(\])/',
|
|
'/>>(.*)\r\n/'
|
|
);
|
|
|
|
$replace = array (
|
|
'<strong>$2</strong>',
|
|
'<em>$2</em>',
|
|
'<u>$2</u>',
|
|
'<s>$2</s>',
|
|
'<h2>$2</h2>',
|
|
'<span class=spoiler tabindex="0">$2</span>',
|
|
'<li>$2</li>',
|
|
'<a href="$2" target="_blank">$2</a>',
|
|
'<quote>>>$1$2</quote><br>'
|
|
);
|
|
|
|
return preg_replace($search, $replace, $text);
|
|
|
|
}
|
|
|
|
// check if the ip has already passed the portal, in this case return.
|
|
// if not, display a simple text and button to click to proceed.
|
|
// the page displayed is done with inline styling, so that no
|
|
// additional files will be requested.
|
|
// Update: what started with the checking of the ip, has now expanded to
|
|
// up to six parameters, which are concantenated and hashed.
|
|
function check_portal_mob($db, $settings, $ip)
|
|
{
|
|
|
|
if ( ($settings['enable_portal'] != TRUE) ) {
|
|
return;
|
|
}
|
|
|
|
if ( ($settings['enable_portal_tor'] != TRUE)
|
|
&& ($_SERVER['REMOTE_ADDR'] == '127.0.0.1') ) {
|
|
return;
|
|
}
|
|
|
|
$current = time();
|
|
$max_age = $current - ($settings['portal_lifetime'] * 60);
|
|
// lifetime is in minutes, so times 60 to go to seconds
|
|
|
|
if ($settings['auto_prolong_portal'] == TRUE) {
|
|
$statement = $db->prepare("SELECT unix_timestamp
|
|
FROM logs
|
|
WHERE type = 'portal'
|
|
AND ip = '$ip'
|
|
AND event in ('pass',
|
|
'visit')
|
|
AND unix_timestamp > '$max_age'
|
|
ORDER BY ROWID DESC LIMIT 1");
|
|
} else {
|
|
$statement = $db->prepare("SELECT unix_timestamp
|
|
FROM logs
|
|
WHERE type = 'portal'
|
|
AND ip = '$ip'
|
|
AND event in ('pass')
|
|
AND unix_timestamp > '$max_age'
|
|
ORDER BY ROWID DESC LIMIT 1");
|
|
}
|
|
|
|
$result = $statement->execute();
|
|
|
|
$portal_pass = 0;
|
|
|
|
while ($row = $result->fetchArray(SQLITE3_NUM)) {
|
|
$portal_pass++;
|
|
}
|
|
|
|
if ( ($portal_pass > 0) ) {
|
|
// bigger zero means we have the last hit, meaning the ip
|
|
// is known
|
|
$portal_message = 'visit';
|
|
log_event($db, $settings, "portal", $portal_message, $ip);
|
|
return;
|
|
} else {
|
|
$random_string = make_token(10, 'alpha');
|
|
$request = $_SERVER['REQUEST_URI'] . '/random=' . $random_string;
|
|
|
|
header( 'HTTP/1.1 202 Accepted' );
|
|
header( 'Cache-Control: no-store', FALSE );
|
|
|
|
$html_string = "<!DOCTYPE html><html><head><style>"
|
|
. "body {font-size:30px;background-color: black;"
|
|
. "color: #33cccc;text-align: center;width: 30em;"
|
|
. "margin-left: auto;margin-right: auto;}"
|
|
. "input[type=submit] {padding:5px 15px;"
|
|
. "font-size:25px;"
|
|
. "background-color: black;"
|
|
. "color: #33cccc;"
|
|
. "cursor:pointer;"
|
|
. "border: 1px solid #11bbcc;"
|
|
. "-webkit-border-radius: 5px;"
|
|
. "border-radius: 5px;}"
|
|
. "</style></head><body><br><br><br>"
|
|
. "<code>Entry portal: "
|
|
. "Please click the button to proceed.</code>"
|
|
. "<br><br><br><br><br><br><div class='form'>"
|
|
. "<form action='/ep' method='post'>"
|
|
. "<input type='hidden' name='portal' value='$request'>"
|
|
. "<input type='submit' value='Enter'><br>"
|
|
. "</form></div>"
|
|
. "<br><br><br><br><br><br><code>Sorry for this,"
|
|
. " it's just a lowlevel protection "
|
|
. "against scraping bots.</code></body></html>";
|
|
|
|
echo "$html_string";
|
|
|
|
quit($db, '');
|
|
}
|
|
}
|
|
|
|
// Show each post in a thread
|
|
function print_thread_mob($db, $sub, $settings, $org_id)
|
|
{
|
|
|
|
$html_string = '<div class="posts" id="posts">';
|
|
|
|
$statement = $db->prepare("SELECT post_id, org_id, sub, text
|
|
FROM threads WHERE sub = '$sub'
|
|
AND org_id = '$org_id'
|
|
AND shadow = 'no'
|
|
ORDER BY post_id");
|
|
$result = $statement->execute();
|
|
|
|
while ($row = $result->fetchArray(SQLITE3_NUM)) {
|
|
$post_id = "{$row[0]}";
|
|
$org_id = "{$row[1]}";
|
|
$post_text = "{$row[3]}";
|
|
$post_text = break_text(bbcode_to_html_mob($post_text, $settings),
|
|
$settings);
|
|
$id_text = make_id_text($post_id);
|
|
|
|
$html_string .= "<div><div class='message'>#$id_text <br>"
|
|
. "<p id=\"$post_id\"></p><br>"
|
|
. "$post_text<br><br></div><br></div>";
|
|
}
|
|
|
|
$html_string .= '</div>';
|
|
|
|
echo "$html_string";
|
|
|
|
}
|
|
|
|
// Show each post of the overboard (so all original posts in their
|
|
// sequence, including bumps, except for the subs that are excluded)
|
|
function print_overboard_mob($db, $settings, $page)
|
|
{
|
|
|
|
$out = '';
|
|
$pagination = $settings['pagination'];
|
|
|
|
if ( (!empty($settings['no_overboard'])) ) {
|
|
$last = array_pop($settings['no_overboard']);
|
|
|
|
foreach($settings['no_overboard'] as $no_overboard) {
|
|
$str = "'" . $no_overboard . "', ";
|
|
$out .= $str;
|
|
}
|
|
|
|
$out .= "'" . $last . "'";
|
|
|
|
}
|
|
|
|
if ($page == 'all') {
|
|
$statement = $db->prepare("SELECT post_id, org_id, sub, text
|
|
FROM threads
|
|
WHERE org_id = original
|
|
AND shadow = 'no'
|
|
AND sub NOT IN ($out)
|
|
ORDER BY ROWID DESC");
|
|
} elseif ($page > 0) {
|
|
// if the page is defined
|
|
$page_start = ($page - 1) * $settings['pagination'];
|
|
$statement = $db->prepare("SELECT post_id, org_id, sub, text
|
|
FROM threads
|
|
WHERE org_id = original
|
|
AND shadow = 'no'
|
|
AND sub NOT IN ($out)
|
|
ORDER BY ROWID DESC
|
|
LIMIT '$page_start', '$pagination'");
|
|
} else {
|
|
$statement = $db->prepare("SELECT post_id, org_id, sub, text
|
|
FROM threads
|
|
WHERE org_id = original
|
|
AND shadow = 'no'
|
|
AND sub NOT IN ($out)
|
|
ORDER BY ROWID DESC
|
|
LIMIT '$pagination'");
|
|
}
|
|
|
|
$result = $statement->execute();
|
|
|
|
echo '<div class="posts" id="posts">';
|
|
|
|
while ($row = $result->fetchArray(SQLITE3_NUM)) {
|
|
|
|
$html_string = '<div class="message first">';
|
|
|
|
$post_id = "{$row[0]}";
|
|
$org_id = "{$row[1]}";
|
|
$sub = "{$row[2]}";
|
|
$text = "{$row[3]}";
|
|
$post_text = break_text(bbcode_to_html_mob($text, $settings));
|
|
|
|
$link_string_1 = "/mob/r/$sub/$org_id/op";
|
|
$link_string_2 = "/mob/r/$sub/$org_id";
|
|
$link_string_3 = "/mob/s/$sub";
|
|
|
|
$html_string .= "<a href='$link_string_3'>$sub</a> "
|
|
. "<a href='$link_string_1'>#$post_id</a>"
|
|
. "<br>$post_text<br>"
|
|
. "<a href='$link_string_2'>reply</a></div>";
|
|
|
|
echo "$html_string";
|
|
|
|
if ($page == 'all') {
|
|
print_replies_mob($db, $sub, $post_id, $org_id,
|
|
$settings, 'open');
|
|
} else {
|
|
print_replies_mob($db, $sub, $post_id, $org_id,
|
|
$settings, 'closed');
|
|
}
|
|
|
|
echo '<hr /><hr />';
|
|
}
|
|
|
|
}
|
|
|
|
// Show each post of an individual feed
|
|
function print_individual_feed_mob($db, $settings, $ex_subs, $in_subs)
|
|
{
|
|
|
|
echo '<div class="posts" id="posts">';
|
|
|
|
$counter = 0;
|
|
|
|
if ( (!empty($ex_subs)) ) {
|
|
$out = '';
|
|
$last = array_pop($ex_subs);
|
|
|
|
foreach($ex_subs as $ex_sub) {
|
|
$str = "'" . $ex_sub . "', ";
|
|
$out .= $str;
|
|
}
|
|
|
|
$out .= "'" . $last . "'";
|
|
|
|
$statement = $db->prepare("SELECT post_id, org_id, sub, text
|
|
FROM threads
|
|
WHERE org_id = original
|
|
AND shadow = 'no'
|
|
AND sub NOT IN ($out)
|
|
ORDER BY ROWID DESC");
|
|
} elseif ( (!empty($in_subs)) ) {
|
|
$in = '';
|
|
$last = array_pop($in_subs);
|
|
|
|
foreach($in_subs as $in_sub) {
|
|
$str = "'" . $in_sub . "', ";
|
|
$in .= $str;
|
|
}
|
|
|
|
$in .= "'" . $last . "'";
|
|
|
|
$statement = $db->prepare("SELECT post_id, org_id, sub, text
|
|
FROM threads
|
|
WHERE org_id = original
|
|
AND shadow = 'no'
|
|
AND sub IN ($in)
|
|
ORDER BY ROWID DESC");
|
|
}
|
|
|
|
$result = $statement->execute();
|
|
|
|
while ($row = $result->fetchArray(SQLITE3_NUM)) {
|
|
|
|
$html_string = '<div class="message first">';
|
|
|
|
$counter++;
|
|
|
|
$post_id = "{$row[0]}";
|
|
$org_id = "{$row[1]}";
|
|
$sub = "{$row[2]}";
|
|
$text = "{$row[3]}";
|
|
|
|
$post_text = break_text(bbcode_to_html_mob($text, $settings));
|
|
|
|
$link_string_1 = "/mob/r/$sub/$org_id/op";
|
|
$link_string_2 = "/mob/r/$sub/$org_id";
|
|
$link_string_3 = "/mob/s/$sub";
|
|
|
|
$html_string .= "<a href='$link_string_3'>$sub</a> "
|
|
. "<a href='$link_string_1'>#$post_id</a>"
|
|
. "<br>$post_text<br>"
|
|
. "<a href='$link_string_2'>reply</a></div>";
|
|
|
|
echo "$html_string";
|
|
|
|
print_replies_mob($db, $sub, $post_id, $org_id, $settings);
|
|
|
|
echo '<br>';
|
|
}
|
|
|
|
return $counter;
|
|
}
|
|
|
|
// Print the hamburger menu with the links
|
|
function print_hamburger_menu($db, $settings, $sub, $total_posts, $page)
|
|
{
|
|
$html_string = '<div class="menu-container">'
|
|
. "<h3>$sub</h3>"
|
|
. '<input type="checkbox" id="menu-toggle"'
|
|
. ' class="menu-toggle">'
|
|
. '<label for="menu-toggle" class="hamburger">'
|
|
. '<div class="bar"></div>'
|
|
. '<div class="bar"></div>'
|
|
. '<div class="bar"></div>'
|
|
. '</label>'
|
|
. '<nav class="nav">'
|
|
. '<ul>';
|
|
if ( $sub != 'overboard' ){
|
|
$html_string .= '<li><a href="/mob/s/overboard">overboard</a></li>';
|
|
} elseif ( $sub != 'main' ){
|
|
$html_string .= '<li><a href="/mob/s/main">main</a></li>';
|
|
}
|
|
$html_string .= '<li><a href="/mob/su">navigation</a></li>'
|
|
. '<div class="bar"></div>'
|
|
. "<li><a href='/d/$sub'>save $sub</a></li>";
|
|
|
|
|
|
if ( ($total_posts > $settings['pagination']) && ($page != 'all') ) {
|
|
$number_first_message = ($page - 1) * $settings['pagination'] + 1;
|
|
$number_last_message =
|
|
$number_first_message + $settings['pagination'] - 1;
|
|
|
|
if ($number_last_message > $total_posts) {
|
|
$number_last_message = $total_posts;
|
|
}
|
|
|
|
$next_page = $page + 1;
|
|
$prev_page = $page - 1;
|
|
$pages_total = ceil($total_posts / $settings['pagination']);
|
|
|
|
$link_string_1 = "/mob/s/$sub/$next_page";
|
|
$link_string_2 = "/mob/s/$sub/$prev_page";
|
|
$link_string_3 = "/mob/s/$sub/all";
|
|
|
|
if ( ($number_first_message > 1)
|
|
&& ($number_last_message < $total_posts) ) {
|
|
$html_string .= "<li><a href='$link_string_1'>show older</a></li>"
|
|
. "<li><a href='$link_string_2'>show newer</a></li>"
|
|
. "<li><a href='$link_string_3'>show all</li>";
|
|
} elseif ($number_last_message == $total_posts) {
|
|
$html_string .= "<li><a href='$link_string_2'>show newer</a></li>"
|
|
. "<li><a href='$link_string_3'>show all</li>";
|
|
|
|
} else {
|
|
$html_string .= "<li><a href='$link_string_1'>show older</a></li>"
|
|
. "<li><a href='$link_string_3'>show all</li>";
|
|
|
|
}
|
|
}
|
|
|
|
$html_string .= '</ul></nav></div>';
|
|
|
|
echo "$html_string";
|
|
|
|
}
|
|
|
|
// Give all the http-headers to the client, mostly for opsec reasons.
|
|
// After, print the html header to open the document for the browser.
|
|
function print_header_mob()
|
|
{
|
|
|
|
// header( 'Content-Type: text/html; charset=utf-8');
|
|
// header( 'X-Frame-Options: DENY', FALSE);
|
|
// header( 'HTTP Cross-Origin-Opener-Policy: same-origin', FALSE);
|
|
// header( 'Cross-Origin-Resource-Policy: same-site', FALSE);
|
|
// header( 'Permissions-Policy: geolocation=(), camera=(), microphone=()',
|
|
// FALSE);
|
|
// header( 'Permissions-Policy: interest-cohort=()', FALSE);
|
|
// header( 'Server: webserver', FALSE);
|
|
// header( 'X-DNS-Prefetch-Control: off', FALSE);
|
|
// header( 'Cache-Control: no-cache', FALSE);
|
|
// header( 'Pragma: no-cache', FALSE);
|
|
|
|
|
|
// nginx used to throw an error with those, and gave back 502 - bad gateway
|
|
// everything worked in latest tests, but reasons are not understood.
|
|
// if problems, comment out all the lines above
|
|
|
|
$html_string = '<!DOCTYPE html><html lang="en"><head>'
|
|
. '<meta charset="UTF-8">'
|
|
. '<meta name="viewport" content="width=device-width,'
|
|
. ' initial-scale=1.0"><!-- Main stylesheet -->'
|
|
. ' <link rel="stylesheet" href="/css/mobile.css"> '
|
|
. '<!-- Themes are now modular and easy to modify -->'
|
|
. '<link rel="stylesheet" href="/css/dirtpathmobile.css">';
|
|
|
|
echo "$html_string";
|
|
}
|
|
|
|
// Show all replies to a given post
|
|
function print_replies_mob($db, $sub, $post_id, $org_id, $settings, $state)
|
|
{
|
|
$sub_statement = $db->prepare("SELECT post_id, org_id,
|
|
sub, text, timestamp,
|
|
name, tripcode
|
|
FROM threads
|
|
WHERE sub = '$sub'
|
|
AND org_id = '$org_id'
|
|
AND org_id != original
|
|
AND shadow = 'no'");
|
|
$sub_result = $sub_statement->execute();
|
|
|
|
$answers = array();
|
|
$counter = 0;
|
|
|
|
while ($row = $sub_result->fetchArray(SQLITE3_NUM)) {
|
|
$sub_post_id = "{$row[0]}";
|
|
$sub_org_id = "{$row[1]}";
|
|
$sub_text = "{$row[3]}";
|
|
$sub_timestamp = "{$row[4]}";
|
|
$sub_name = "{$row[5]}";
|
|
$sub_tripcode = "{$row[6]}";
|
|
if ($sub_post_id != $sub_org_id) {
|
|
$counter++;
|
|
$post = array();
|
|
$sub_post_text = break_text(bbcode_to_html_mob
|
|
($sub_text, $settings, $sub));
|
|
array_push($post, $sub_post_id);
|
|
array_push($post, $sub_org_id);
|
|
array_push($post, $sub_post_text);
|
|
array_push($post, $sub_timestamp);
|
|
array_push($post, $sub_name);
|
|
array_push($post, $sub_tripcode);
|
|
array_push($answers, $post);
|
|
}
|
|
}
|
|
|
|
$display_number = $counter - 1;
|
|
|
|
if ($counter == 0) {
|
|
// no replies exist for this message
|
|
return;
|
|
}
|
|
|
|
$last_answer = array_pop($answers);
|
|
$last_post_id = $last_answer[0];
|
|
$last_post_text = $last_answer[2];
|
|
$last_post_timestamp = $last_answer[3];
|
|
$last_post_name = $last_answer[4];
|
|
$last_post_tripcode = $last_answer[5];
|
|
|
|
$html_string = '';
|
|
|
|
if ($counter > 1) {
|
|
// we have at least one reply
|
|
if ($state == 'open') {
|
|
$html_string .= "<details open>";
|
|
} else {
|
|
$html_string .= "<details>";
|
|
}
|
|
|
|
$html_string .= "<summary>Show $display_number more replies</summary>";
|
|
|
|
foreach ($answers as $display_msg) {
|
|
$answer_post_id = $display_msg[0];
|
|
$answer_post_text = $display_msg[2];
|
|
$answer_post_timestamp = $display_msg[3];
|
|
$answer_post_name = $display_msg[4];
|
|
$answer_post_tripcode = $display_msg[5];
|
|
|
|
$link_string_1 = "/mob/r/$sub/$org_id/$answer_post_id/5";
|
|
|
|
$html_string .= "<div class='message replies'>"
|
|
. "<p id=\"$answer_post_id" . "_" . "$sub\"></p>"
|
|
. "<a href='$link_string_1'>#$answer_post_id</a>";
|
|
|
|
if ( !empty($answer_post_timestamp) &&
|
|
$settings['enable_timestamps'] ) {
|
|
$html_string .= "<small>:$answer_post_timestamp</small>";
|
|
}
|
|
|
|
$html_string .= "<br><br><code>$answer_post_text</code><br><br>";
|
|
|
|
if ( !empty($answer_post_name) &&
|
|
$settings['enable_edit']) {
|
|
$html_string .= "<a href='/e/$sub/$answer_post_id'>edit</a> ";
|
|
}
|
|
|
|
if ( !empty($answer_post_name) &&
|
|
$settings['enable_tripcodes']) {
|
|
$name_string = $answer_post_name;
|
|
$link_string_4 = "/mob/u/$name_string";
|
|
$html_string .= "<a href='$link_string_4'>$name_string</a>";
|
|
}
|
|
|
|
$html_string .= '</div>';
|
|
}
|
|
|
|
$html_string .= "</details>";
|
|
}
|
|
|
|
$link_string_1 = "/mob/r/$sub/$org_id/$last_post_id";
|
|
|
|
$html_string .= "<div class='message last'>"
|
|
. "<p id=\"$last_post_id" . "_" . "$sub\"></p>"
|
|
. "<a href='$link_string_1'>#$last_post_id</a>";
|
|
|
|
if ( !empty($last_post_timestamp) &&
|
|
$settings['enable_timestamps'] ) {
|
|
$html_string .= "<small>:$last_post_timestamp</small>";
|
|
}
|
|
|
|
$html_string .= "<br><br>$last_post_text<br><br>";
|
|
|
|
if ( !empty($last_post_name) &&
|
|
$settings['enable_edit']) {
|
|
$html_string .= "<a href='/mob/e/$sub/$last_post_id'>edit</a> ";
|
|
}
|
|
|
|
if ( !empty($last_post_name) &&
|
|
$settings['enable_tripcodes']) {
|
|
$name_string = $last_post_name;
|
|
$link_string_4 = "/mob/u/$name_string";
|
|
$html_string .= "<a href='$link_string_4'>$name_string</a>";
|
|
}
|
|
|
|
$html_string .= '</div>';
|
|
|
|
echo "$html_string";
|
|
}
|
|
|
|
|
|
// Show each post in a sub
|
|
function print_sub_mob($db, $sub, $settings, $page)
|
|
{
|
|
|
|
echo '<div class="posts" id="posts">';
|
|
|
|
$pagination = $settings['pagination'];
|
|
|
|
if ($page == 'all') {
|
|
$statement = $db->prepare("SELECT post_id, org_id, sub, text
|
|
FROM threads
|
|
WHERE sub = '$sub'
|
|
AND shadow = 'no'
|
|
AND original = org_id
|
|
ORDER BY ROWID DESC");
|
|
} elseif ($page > 0) {
|
|
// if the page is defined
|
|
$page_start = ($page - 1) * $settings['pagination'];
|
|
$statement = $db->prepare("SELECT post_id, org_id, sub, text
|
|
FROM threads
|
|
WHERE sub = '$sub'
|
|
AND shadow = 'no'
|
|
AND original = org_id
|
|
ORDER BY ROWID DESC
|
|
LIMIT '$page_start', '$pagination'");
|
|
} else {
|
|
$statement = $db->prepare("SELECT post_id, org_id, sub, text
|
|
FROM threads
|
|
WHERE sub = '$sub'
|
|
AND shadow = 'no'
|
|
AND original = org_id
|
|
ORDER BY ROWID DESC
|
|
LIMIT '$pagination'");
|
|
}
|
|
|
|
$result = $statement->execute();
|
|
|
|
while ($row = $result->fetchArray(SQLITE3_NUM)) {
|
|
|
|
$html_string = '<div class="message first">';
|
|
|
|
$post_id = "{$row[0]}";
|
|
$org_id = "{$row[1]}";
|
|
$text = "{$row[3]}";
|
|
$post_text = break_text(bbcode_to_html_mob($text, $settings));
|
|
|
|
$id_text = make_id_text($post_id);
|
|
$link_string_1 = "/mob/r/$sub/$org_id/op";
|
|
$link_string_2 = "/mob/r/$sub/$org_id";
|
|
|
|
$html_string .= "<a href='$link_string_1'>#$id_text</a>"
|
|
. "<br>$post_text<br>"
|
|
. "<a href='$link_string_2'>reply</a></div>";
|
|
|
|
echo "$html_string";
|
|
|
|
if ($page == 'all') {
|
|
print_replies_mob($db, $sub, $post_id, $org_id,
|
|
$settings, 'open');
|
|
} else {
|
|
print_replies_mob($db, $sub, $post_id, $org_id,
|
|
$settings, 'closed');
|
|
}
|
|
|
|
echo '<hr /><hr />';
|
|
}
|
|
|
|
echo "</div>";
|
|
|
|
}
|
|
|
|
// In case of replies, check which post we are replying to
|
|
// (based on the pretty vars in GET requests)
|
|
function set_org_id_mob()
|
|
{
|
|
|
|
$org_id = read_pretty_vars(4, 'number', 10);
|
|
// we read from the third position, and a message does not need more
|
|
// than 10 digits (=max 9 999 999 999 messages)
|
|
return $org_id;
|
|
|
|
}
|
|
|
|
// Get the page if it is defined, otherwise set to 1
|
|
function set_page_mob()
|
|
{
|
|
$page = read_pretty_vars(4, 'number', 10);
|
|
// read from fourth position, and a page does not need more
|
|
// than 10 digits
|
|
|
|
if ( ($page < 1) ) {
|
|
// if the page is zero, it means we did not
|
|
// get a number before
|
|
|
|
$page = read_pretty_vars(4, 'alnum', 3);
|
|
// read from the third position, and "all" has three letters
|
|
|
|
if ( ($page != 'all') ) {
|
|
|
|
$page = 1;
|
|
// if page is not "all", we start with the first
|
|
}
|
|
}
|
|
|
|
return $page;
|
|
}
|
|
|
|
// Get the quote, if there is one.
|
|
function set_quote_mob()
|
|
{
|
|
|
|
if (get_pretty_vars_count() == 7) {
|
|
$quote = read_pretty_vars(5, 'alnum', 10);
|
|
// read from fourth position, and a post id does not need more
|
|
// than 10 digits
|
|
} else {
|
|
$quote = '';
|
|
}
|
|
|
|
return $quote;
|
|
|
|
}
|
|
|
|
// Determine which sub we use currently, first read from POST,
|
|
// than from the pretty vars (GET)
|
|
function set_sub_mob($settings)
|
|
{
|
|
|
|
$sub = '';
|
|
|
|
if ( (!empty($_POST['sub'])) ) {
|
|
$sub = filter($_POST['sub'], 'alnum', $settings['max_name_sub']);
|
|
} elseif (get_pretty_vars_count() > 1) {
|
|
$sub = read_pretty_vars(3, 'alnum', $settings['max_name_sub']);
|
|
// read the sub from the third position
|
|
}
|
|
|
|
if ($sub == '') {
|
|
$sub = 'main';
|
|
}
|
|
|
|
return $sub;
|
|
}
|
|
|
|
// Show the postform with or without the captcha (according to setting),
|
|
// if on main show also the field to create new subs
|
|
function show_post_form_mob($db, $msg, $sub, $settings, $org_id, $quote, $ip)
|
|
{
|
|
|
|
if ( (check_free_space($db, $settings) == FALSE) ) {
|
|
echo '<h3>No posting possible, no space on filesystem</h3>';
|
|
return;
|
|
}
|
|
|
|
if ( (post_block_user($db, $settings, $ip) != TRUE) ) {
|
|
echo '<h3>Max posts exhausted. Retry later.</h3>';
|
|
return;
|
|
}
|
|
|
|
$html_string = '<form action="/mob/p" method="POST" class="box-input">';
|
|
|
|
if ( ($sub != 'main') ) {
|
|
$html_string .= "<input type='hidden' name='sub' value='$sub'>";
|
|
}
|
|
|
|
if ( (!empty($org_id)) ) {
|
|
$html_string .= "<input type='hidden' name='org_id' value='$org_id'>";
|
|
}
|
|
|
|
$token = make_token(250, 'alnum');
|
|
|
|
$html_string .= "<input type='hidden' name='post_token' value='$token'>"
|
|
. '<textarea id="text" name="text"'
|
|
. ' placeholder="Say something"></textarea>'
|
|
. '<button type="submit" id="send-button">Send</button>'
|
|
. '</form>';
|
|
|
|
$current = time();
|
|
$hash = hash('sha512', $token);
|
|
|
|
$statement = $db->prepare("INSERT OR IGNORE INTO captchas(hash, unix_timestamp)
|
|
VALUES ('$hash', '$current')");
|
|
$statement->execute();
|
|
|
|
echo "$html_string";
|
|
}
|
|
|
|
// Show the existing subs to a user, including their count
|
|
// Differentiates between subs with > 10 posts (high-traffic)
|
|
// and lower (low-traffic). Also shows the last five subs that
|
|
// were posted to.
|
|
function show_subs_count_mob($db, $settings)
|
|
{
|
|
$out = '';
|
|
|
|
if ( (!empty($settings['no_overboard'])) ) {
|
|
$last = array_pop($settings['no_overboard']);
|
|
|
|
foreach($settings['no_overboard'] as $no_overboard) {
|
|
$str = "'" . $no_overboard . "', ";
|
|
$out .= $str;
|
|
}
|
|
|
|
$out .= "'" . $last . "'";
|
|
|
|
}
|
|
|
|
$statement = $db->prepare("SELECT post_id
|
|
FROM threads
|
|
WHERE sub NOT IN ($out)
|
|
AND shadow = 'no'");
|
|
$result = $statement->execute();
|
|
$counter = 0;
|
|
|
|
while ($row = $result->fetchArray(SQLITE3_NUM)) {
|
|
$counter++;
|
|
}
|
|
|
|
$statement = $db->prepare("SELECT post_id
|
|
FROM threads
|
|
WHERE sub NOT IN ($out)
|
|
AND shadow = 'no'
|
|
AND post_id = org_id");
|
|
$result = $statement->execute();
|
|
$counter_org = 0;
|
|
|
|
while ($row = $result->fetchArray(SQLITE3_NUM)) {
|
|
$counter_org++;
|
|
}
|
|
|
|
$replies = $counter - $counter_org;
|
|
|
|
$html_string = "<h3> Subs with some traffic:</h3>"
|
|
. '<div class="message first">'
|
|
. "<a href=/mob/s/overboard>overboard"
|
|
. "($counter_org/$replies)</a></div>";
|
|
|
|
$statement = $db->prepare("SELECT DISTINCT sub
|
|
FROM threads
|
|
WHERE shadow = 'no'
|
|
ORDER BY sub
|
|
COLLATE NOCASE");
|
|
$result = $statement->execute();
|
|
|
|
$high_traffic_subs = array();
|
|
$low_traffic_subs = array();
|
|
|
|
while ($row = $result->fetchArray(SQLITE3_NUM)) {
|
|
$display_sub = array();
|
|
$sub = "{$row[0]}";
|
|
$total_posts = give_total_posts($db, $sub, FALSE, $settings);
|
|
$total_org_posts = give_total_posts($db, $sub, TRUE, $settings);
|
|
$replies = $total_posts - $total_org_posts;
|
|
|
|
array_push($display_sub, $sub);
|
|
array_push($display_sub, $total_org_posts);
|
|
array_push($display_sub, $replies);
|
|
|
|
if ( ($total_posts > 10) ) {
|
|
// we define any sub with more than ten messages as high traffic
|
|
// anything below as low traffic
|
|
array_push($high_traffic_subs, $display_sub);
|
|
} else {
|
|
array_push($low_traffic_subs, $display_sub);
|
|
}
|
|
}
|
|
|
|
|
|
foreach($high_traffic_subs as $display_sub) {
|
|
$html_string .= '<div class="message first">'
|
|
. "<a href=/mob/s/$display_sub[0]>$display_sub[0]"
|
|
. "($display_sub[1]/$display_sub[2])</a></div>";
|
|
}
|
|
|
|
$html_string .= '<br><br><br><h3>Other subs:</h3>';
|
|
|
|
$temp = array_reverse($low_traffic_subs);
|
|
$first_display_sub = array_pop($temp);
|
|
$low_traffic_subs = array_reverse($temp);
|
|
|
|
$html_string .= '<div class="message first">'
|
|
. "<a href=/mob/s/$first_display_sub[0]>"
|
|
. "$first_display_sub[0]"
|
|
. "($first_display_sub[1]/$first_display_sub[2])</a></div>";
|
|
|
|
foreach($low_traffic_subs as $display_sub) {
|
|
$html_string .= '<div class="message first">'
|
|
. "<a href=/mob/s/$display_sub[0]>$display_sub[0]"
|
|
. "($display_sub[1]/$display_sub[2])</a></div>";
|
|
}
|
|
|
|
$statement = $db->prepare("SELECT DISTINCT sub
|
|
FROM threads
|
|
WHERE shadow = 'no'
|
|
ORDER BY ROWID DESC
|
|
LIMIT 5");
|
|
$result = $statement->execute();
|
|
|
|
$html_string .= '<br><br><br><h3>Subs with recent posts:</h3>';
|
|
|
|
while ($row = $result->fetchArray(SQLITE3_NUM)) {
|
|
$sub = "{$row[0]}";
|
|
$html_string .= '<div class="message first">'
|
|
. "<a href=/mob/s/$sub>$sub</a></div>";
|
|
}
|
|
|
|
echo "$html_string";
|
|
}
|
|
|
|
// Show the existing subs to a user, without the count
|
|
function show_subs_no_count_mob($db)
|
|
{
|
|
|
|
$html_string = "<h3><a href=/mob/s/overboard>overboard</a>";
|
|
|
|
$statement = $db->prepare("SELECT DISTINCT sub
|
|
FROM threads
|
|
WHERE shadow = 'no'
|
|
ORDER BY sub
|
|
COLLATE NOCASE");
|
|
$result = $statement->execute();
|
|
|
|
while ($row = $result->fetchArray(SQLITE3_NUM)) {
|
|
$sub = "{$row[0]}";
|
|
if ( ($sub != '') ) {
|
|
$html_string .= " | <a href=/mob/s/$sub>$sub</a>";
|
|
}
|
|
}
|
|
|
|
$html_string .= '</h3>';
|
|
|
|
echo "$html_string";
|
|
}
|
|
|
|
// EOF
|