dev_endboard/opt/show_tools.php

509 lines
17 KiB
PHP

<?php
/*
* This is the endboard software, version beta 0.73
* It is a textboard written for the use in the darknets.
*
* This file holds the functions used to show subs, forms and post history.
* It can be included without side effects.
*
* 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.
*/
function get_first_post_text($db, $sub, $settings)
{
if ( ($sub == 'main') ){
return $settings['hover_title_main'];
}
$statement = $db->prepare("SELECT text
FROM threads
WHERE shadow = 'no'
AND sub = '$sub'
ORDER BY post_id ASC
LIMIT 1");
$result = $statement->execute();
while ($row = $result->fetchArray(SQLITE3_NUM)) {
$title = "{$row[0]}";
$title = htmlspecialchars($title, ENT_QUOTES, 'UTF-8');
}
return $title;
}
// Show the form to edit a post, prefilled with the original post
function show_edit_form($db, $sub, $post_id, $ip, $css, $settings)
{
if ( (check_free_space($db, $settings) == FALSE) ) {
echo '<h1>No editing possible, no space on filesystem</h1>';
return;
}
if ( (post_block_user($db, $settings, $ip) != TRUE) ) {
echo '<h1>Max posts exhausted. Retry later.</h1>';
return;
}
$statement = $db->prepare("SELECT text, original
FROM threads
WHERE sub = '$sub'
AND shadow = 'no'
AND post_id = '$post_id'
");
$result = $statement->execute();
while ($row = $result->fetchArray(SQLITE3_NUM)) {
$post_text = "{$row[0]}";
$original = "{$row[1]}";
}
$html_string = "<div class='form'><form action='/e' method='post'>"
. "<table class='newpost'>"
. "<input type='hidden' name='css' value='$css'>"
. "<input type='hidden' name='sub' value='$sub'>"
. '<tr><td><textarea rows=\'10\' cols=\'56\' name=\'edit_text\' '
. "required >$post_text</textarea></td></tr>"
. "<input type='hidden' name='original' value='$original'>"
. "<input type='hidden' name='post_id' value='$post_id'>";
$token = make_token(250);
$current = time();
$hash = hash('sha512', $token);
$html_string .= "<input type='hidden' name='post_token' "
. "value='$token'><tr><td>"
. "<textarea "
. "name='edit_combination' "
. "placeholder='Enter name#tripkey'></textarea>";
if ($settings['enable_timestamps']) {
$html_string .= "<input type='checkbox' value='timestamp' name='edit_timestamp'"
. "id='timestamp'><span class=\"label timestamp\">timestamp</span>";
}
$html_string .= "<input type='submit' value='Edit post'><br></td>";
$html_string .= '</table></form></div><hr>';
$statement = $db->prepare("INSERT OR IGNORE
INTO captchas(hash, unix_timestamp)
VALUES ('$hash', '$current')");
$statement->execute();
echo "$html_string";
}
// 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($db, $msg, $sub, $settings, $org_id, $css, $quote, $ip)
{
if ( (check_free_space($db, $settings) == FALSE) ) {
echo '<h1>No posting possible, no space on filesystem</h1>';
return;
}
if ( (post_block_user($db, $settings, $ip) != TRUE) ) {
echo '<h1>Max posts exhausted. Retry later.</h1>';
return;
}
$html_string = "<div class='form'><form action='/p' method='post'>"
. "<table class='newpost'>"
. "<input type='hidden' name='css' value='$css'>";
if ( (!$org_id) &&
($sub == 'main') &&
($settings['enable_sub_creation'] == TRUE) ) {
$html_string .= "<tr><td><input type='text' name='sub' value='$sub' "
. "placeholder='name of sub'>";
}
if ( ($sub != 'main') ) {
$html_string .= "<input type='hidden' name='sub' value='$sub'>";
}
$html_string .= '<tr><td><textarea rows=\'10\' cols=\'56\' name=\'text\' ';
if ( (!empty($quote)) ) {
$html_string .= "required >>> $quote</textarea></td></tr>";
} else {
$html_string .= 'required placeholder=\'[b bold], [i italic],'
. '[li list point], [s strike through], [sp spoiler],'
. '[h headline], [u underlined], [url link], '
. '>> $post_id: local reference,'
. ' s/$sub/$post_id: global reference\'>'
. '</textarea></td></tr>';
}
if ( (!empty($org_id)) ) {
$html_string .= "<input type='hidden' name='org_id' value='$org_id'>";
}
$token = make_token(250);
$current = time();
if ($settings['use_captcha']) {
$math_one = rand(20,80);
$math_two = rand(1,19);
// the first number should be bigger than the next, to avoid
// negative results. Also, results should be below 100.
$math_type = rand(0,1);
// 0 means +, 1 means -
if ($math_type == 0) {
$answer = $math_one + $math_two;
$math_type = '+';
} elseif ($math_type == 1) {
$answer = $math_one - $math_two;
$math_type = '-';
}
$summary = ($math_one . $math_two . $math_type . $answer . $token);
$hash = hash('sha512', $summary);
$html_string .= "<tr><td><input type='hidden' name='math_one'"
. " value='$math_one'><input type='hidden' "
. "name='math_two' value='$math_two'>"
. "<input type='hidden' name='math_type' "
. "value='$math_type'><input type='hidden' "
. "name='post_token' value='$token'>$math_one "
. "$math_type $math_two <input type='text' "
. "required name='math_answer' maxlength=3 size=3 "
. "placeholder='???'>";
} else {
$hash = hash('sha512', $token);
$html_string .= "<input type='hidden' name='post_token' "
. "value='$token'><tr><td>";
}
if ( ($settings['enable_tripcodes']) ) {
$combination = make_tripcode($settings);
$html_string .= "<textarea "
. "name='combination' "
. ">$combination</textarea>"
. "<input type='hidden' name='combination_hidden'"
. " value='$combination'>";
}
if ( ($settings['enable_sage']) &&
(!empty($org_id)) ){
$html_string .= "<input type='checkbox' value='sage' name='sage'"
. "id='sage'><span class=\"label sage\">sage</span>";
}
if ($settings['enable_timestamps']) {
$html_string .= "<input type='checkbox' value='timestamp' name='timestamp'"
. "id='timestamp'><span class=\"label timestamp\">timestamp</span>";
}
$html_string .= "<input type='submit' value='Post this'><br></td>";
$html_string .= '</table></form></div><hr>';
$statement = $db->prepare("INSERT OR IGNORE
INTO captchas(hash, unix_timestamp)
VALUES ('$hash', '$current')");
$statement->execute();
echo "$html_string";
}
// Shows all versions of a specific post
function show_post_history($db, $sub, $post_id, $settings)
{
$html_string = '<div class=\'postcontainer\'>';
$statement = $db->prepare("SELECT original
FROM threads
WHERE sub = '$sub'
AND post_id = '$post_id'
");
$result = $statement->execute();
while ($row = $result->fetchArray(SQLITE3_NUM)) {
$original = "{$row[0]}";
}
$statement = $db->prepare("SELECT post_id, org_id, sub, text, timestamp,
name, tripcode
FROM threads
WHERE sub = '$sub'
AND original = '$original'
ORDER BY post_id");
$result = $statement->execute();
$posts = array();
$counter = 0;
while ($row = $result->fetchArray(SQLITE3_NUM)) {
$counter++;
$post = array();
$post_id = "{$row[0]}";
$org_id = "{$row[1]}";
$post_text = "{$row[3]}";
$post_text = break_text(bbcode_to_html($post_text, $settings, $sub),
$settings);
$id_text = make_id_text($post_id);
$timestamp = "{$row[4]}";
$name = "{$row[5]}";
$tripcode = "{$row[6]}";
array_push($post, $post_id);
array_push($post, $org_id);
array_push($post, $post_text);
array_push($post, $id_text);
array_push($post, $timestamp);
array_push($post, $name);
array_push($post, $tripcode);
array_push($posts, $post);
}
$display = array_reverse($posts);
foreach ($display as $old_post) {
$post_id = "$old_post[0]";
$org_id = "$old_post[1]";
$post_text = "$old_post[2]";
$id_text = $old_post[3];
$timestamp = "$old_post[4]";
$name = "$old_post[5]";
$tripcode = "$old_post[6]";
$html_string .= "<div><p id=\"$post_id" . "_" . "$sub\"></p>"
. "<div class='post'>#$id_text <br><br>"
. "$post_text<br><br></div><br></div>";
}
$html_string .= '</div>';
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 ten subs that
// were posted to.
function show_subs_count($db, $css, $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;
$title = $settings['hover_title_overboard'];
$html_string = "<h1> Subs with some traffic:</h1><h1>"
. "<a href=/s/overboard/$css"
. " title=\"$title\">overboard"
. "($counter_org/$replies)</a>";
$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);
$title = get_first_post_text($db, $sub, $settings);
array_push($display_sub, $title);
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) {
$title = $display_sub[3];
$html_string .= " | <a href=/s/$display_sub[0]/$css"
. " title=\"$title\">$display_sub[0]"
. "($display_sub[1]/$display_sub[2])</a>";
}
$html_string .= '</h1><br><br><br><h1>Other subs:</h1><h1>';
$temp = array_reverse($low_traffic_subs);
$first_display_sub = array_pop($temp);
$low_traffic_subs = array_reverse($temp);
$title = $first_display_sub[3];
$html_string .= "<a href=/s/$first_display_sub[0]/$css"
. " title=\"$title\">$first_display_sub[0]"
. "($first_display_sub[1]/$first_display_sub[2])</a>";
foreach($low_traffic_subs as $display_sub) {
$title = $display_sub[3];
$html_string .= " | <a href=/s/$display_sub[0]/$css"
. " title=\"$title\">$display_sub[0]"
. "($display_sub[1]/$display_sub[2])</a>";
}
$statement = $db->prepare("SELECT DISTINCT sub
FROM threads
WHERE shadow = 'no'
ORDER BY ROWID DESC
LIMIT 10");
$result = $statement->execute();
$html_string .= '</h1><br>'
. '<br><br><h1>Subs with recent posts:</h1><h1>';
while ($row = $result->fetchArray(SQLITE3_NUM)) {
$sub = "{$row[0]}";
$title = get_first_post_text($db, $sub, $settings);
$html_string .= "<a href=/s/$sub/$css title=\"$title\">$sub</a> ";
}
$html_string .= '</h1>';
echo "$html_string";
}
// Show the existing subs to a user, without the count
function show_subs_no_count($db, $css, $settings)
{
$title = $settings['hover_title_overboard'];
$html_string = "<h1><a href=/s/overboard/$css"
. " title=\"$title\">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 != '') ) {
$title = get_first_post_text($db, $sub, $settings);
$html_string .= " | <a href=/s/$sub/$css title=\"$title\">$sub</a>";
}
}
$html_string .= '</h1>';
echo "$html_string";
}
// Show the form that allows to set individual feeds.
function show_set_feeds_form($db, $settings, $css)
{
$html_string = '<br><br><br><h1>Set your multifeed:<br></h1>'
. '<p id=\'page\'>'
. '<div class=\'form\'><form action=\'/iv\' method=\'post\'>'
. '<table class=\'newpost\'>'
. '<tr><td>Show everything except: </td><td>'
. '<input type=\'text\' name=\'ex_subs\' placeholder=\''
. 'subs you do not want to see\' style=\'width: 500px;\'>'
. '<tr><td>OR Show nothing but: </td><td>'
. '<input type=\'text\' name=\'in_subs\' placeholder=\''
. 'the only subs you want to see\' style=\'width: 500px;\'>'
. '<input type=\'hidden\' name=\'css\' value=\'$css\'>'
. '<tr><td></td><td><input type=\'submit\' '
. 'value=\'Get my feeds\'>'
. '<br></td></tr></table></form></div></h1><hr>';
echo "$html_string";
}
// EOF