rocksolid-light/Rocksolid_Light/rocksolid/newsportal.php

1926 lines
64 KiB
PHP

<?php
/*
* rslight NNTP<->HTTP Gateway
* Download: https://news.novabbs.com/getrslight
*
* Based on Newsportal by Florian Amrhein
*
* E-Mail: retroguy@novabbs.com
* Web: https://news.novabbs.com
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
if (file_exists("lib/types.inc.php"))
include "lib/types.inc.php";
if (file_exists("lib/thread.inc.php"))
include "lib/thread.inc.php";
if (file_exists("lib/message.inc.php"))
include "lib/message.inc.php";
if (file_exists("lib/post.inc.php"))
include "lib/post.inc.php";
$CONFIG = include ($config_file);
/*
* opens the connection to the NNTP-Server
*
* $server: adress of the NNTP-Server
* $port: port of the server
*/
function nntp_open($nserver = 0, $nport = 0)
{
global $text_error, $CONFIG;
global $server, $port;
// echo "<br>NNTP OPEN<br>";
if (! isset($CONFIG['enable_nntp']) || $CONFIG['enable_nntp'] != true) {
$CONFIG['server_auth_user'] = $CONFIG['remote_auth_user'];
$CONFIG['server_auth_pass'] = $CONFIG['remote_auth_pass'];
}
$authorize = ((isset($CONFIG['server_auth_user'])) && (isset($CONFIG['server_auth_pass'])) && ($CONFIG['server_auth_user'] != ""));
if ($nserver == 0)
$nserver = $server;
if ($nport == 0)
$nport = $port;
$ns = @fsockopen($nserver, $nport);
// if the connection to the news server fails, inform the user and stop processing.
if ($ns == false) {
echo '<center><p>' . $text_error["error:"] . " " . $text_error["connection_failed"] . '.</p>';
echo '<br>';
echo '<p>Please wait a few moments and try again. If you see the same error, notify the owner that their Message Server is offline.</p>';
echo '</center>';
exit(0);
}
$weg = line_read($ns); // kill the first line
if (substr($weg, 0, 2) != "20") {
echo "<p>" . $text_error["error:"] . $weg . "</p>";
fclose($ns);
$ns = false;
} else {
if ($ns != false) {
fputs($ns, "MODE reader\r\n");
$weg = line_read($ns); // and once more
if ((substr($weg, 0, 2) != "20") && ((! $authorize) || ((substr($weg, 0, 3) != "480") && ($authorize)))) {
echo "<p>" . $text_error["error:"] . $weg . "</p>";
fclose($ns);
$ns = false;
}
}
if ((isset($CONFIG['server_auth_user'])) && (isset($CONFIG['server_auth_pass'])) && ($CONFIG['server_auth_user'] != "")) {
fputs($ns, "AUTHINFO USER " . $CONFIG['server_auth_user'] . "\r\n");
$weg = line_read($ns);
fputs($ns, "AUTHINFO PASS " . $CONFIG['server_auth_pass'] . "\r\n");
$weg = line_read($ns);
/* Only check auth if reading and posting same server */
// NNTP Response NOT 281 (Authorization failed)
if (substr($weg, 0, 3) != "281" && ! (isset($post_server)) && ($post_server != "")) {
echo "<p>" . $text_error["error:"] . "</p>";
echo "<p>" . $text_error["auth_error"] . "</p>";
}
}
}
if ($ns == false)
echo "<p>" . $text_error["connection_failed"] . "</p>";
return $ns;
}
function nntp2_open($nserver = 0, $nport = 0)
{
global $text_error, $CONFIG;
// echo "<br>NNTP OPEN<br>";
$authorize = ((isset($CONFIG['remote_auth_user'])) && (isset($CONFIG['remote_auth_pass'])) && ($CONFIG['remote_auth_user'] != ""));
if ($nserver == 0)
$nserver = $CONFIG['remote_server'];
if ($nport == 0)
$nport = $CONFIG['remote_port'];
if ($CONFIG['remote_ssl']) {
if ($nport == $CONFIG['remote_port']) {
$nport = $CONFIG['remote_ssl'];
}
var_dump($ns = fsockopen("ssl://" . $nserver, $nport, $error, $errorString, 30));
var_dump($errorString);
var_dump($error);
// $ns=@fsockopen('ssl://'.$nserver.":".$nport);
} else {
if (isset($CONFIG['socks_host']) && $CONFIG['socks_host'] !== '') {
$ns = fsocks4asockopen($CONFIG['socks_host'], $CONFIG['socks_port'], $nserver, $nport);
} else {
$ns = @fsockopen('tcp://' . $nserver . ":" . $nport);
}
}
// $ns=@fsockopen($nserver,$nport);
$weg = line_read($ns); // kill the first line
if (substr($weg, 0, 2) != "20") {
echo "<p>" . $text_error["error:"] . $weg . "</p>";
if ($ns) {
fclose($ns);
}
$ns = false;
} else {
if ($ns != false) {
fputs($ns, "MODE reader\r\n");
$weg = line_read($ns); // and once more
if ((substr($weg, 0, 2) != "20") && ((! $authorize) || ((substr($weg, 0, 3) != "480") && ($authorize)))) {
echo "<p>" . $text_error["error:"] . $weg . "</p>";
fclose($ns);
$ns = false;
}
}
if ((isset($CONFIG['remote_auth_user'])) && (isset($CONFIG['remote_auth_pass'])) && ($CONFIG['remote_auth_user'] != "")) {
fputs($ns, "AUTHINFO USER " . $CONFIG['remote_auth_user'] . "\r\n");
$weg = line_read($ns);
fputs($ns, "AUTHINFO PASS " . $CONFIG['remote_auth_pass'] . "\r\n");
$weg = line_read($ns);
/* Only check auth if reading and posting same server */
if (substr($weg, 0, 3) != "281" && ! (isset($post_server)) && ($post_server != "")) {
echo "<p>" . $text_error["error:"] . "</p>";
echo "<p>" . $text_error["auth_error"] . "</p>";
}
}
}
if ($ns == false)
echo "<p>" . $text_error["connection_failed"] . "</p>";
return $ns;
}
function fsocks4asockopen($proxyHostname, $proxyPort, $targetHostname, $targetPort)
{
$sock = fsockopen($proxyHostname, $proxyPort);
if ($sock === false)
return false;
fwrite($sock, pack("CCnCCCCC", 0x04, 0x01, $targetPort, 0x00, 0x00, 0x00, 0x01, 0x00) . $targetHostname . pack("C", 0x00));
$response = fread($sock, 16);
$values = unpack("xnull/Cret/nport/Nip", $response);
if ($values["ret"] == 0x5a)
return $sock;
else {
fclose($sock);
return false;
}
}
/*
* Close a NNTP connection
*
* $ns: the handle of the connection
*/
function nntp_close(&$ns)
{
if ($ns != false) {
fputs($ns, "QUIT\r\n");
fclose($ns);
}
}
/*
* Validates an email adress
*
* $address: a string containing the email-address to be validated
*
* returns true if the address passes the tests, false otherwise.
*/
function validate_email($address)
{
global $validate_email;
$return = true;
if (($validate_email >= 1) && ($return == true))
/* Need to clean up this regex to work properly with preg_match
$return = (preg_match('^[-!#$%&\'*+\\./0-9=?A-Z^_A-z{|}~]+'.'@'.
'[-!#$%&\'*+\\/0-9=?A-Z^_A-z{|}~]+\.'.
'[-!#$%&\'*+\\./0-9=?A-Z^_A-z{|}~]+$',$address));
*/
$return = 1;
if (($validate_email >= 2) && ($return == true)) {
$addressarray = address_decode($address, "garantiertungueltig");
$return = checkdnsrr($addressarray[0]["host"], "MX");
if (! $return)
$return = checkdnsrr($addressarray[0]["host"], "A");
}
return ($return);
}
/*
* decodes a block of 7bit-data in uuencoded format to it's original
* 8bit format.
* The headerline containing filename and permissions doesn't have to
* be included.
*
* $data: The uuencoded data as a string
*
* returns the 8bit data as a string
*
* Note: this function is very slow and doesn't recognize incorrect code.
*/
function uudecode_line($line)
{
$data = substr($line, 1);
$length = ord($line[0]) - 32;
$decoded = "";
for ($i = 0; $i < (strlen($data) >> 2); $i ++) {
$pack = substr($data, $i << 2, 4);
$upack = "";
$bitmaske = 0;
for ($o = 0; $o < 4; $o ++) {
$g = ((ord($pack[3 - $o]) - 32));
if ($g == 64)
$g = 0;
$bitmaske = $bitmaske | ($g << (6 * $o));
}
$schablone = 255;
for ($o = 0; $o < 3; $o ++) {
$c = ($bitmaske & $schablone) >> ($o << 3);
$schablone = ($schablone << 8);
$upack = chr($c) . $upack;
}
$decoded .= $upack;
}
$decoded = substr($decoded, 0, $length);
return $decoded;
}
/*
* decodes uuencoded Attachments.
*
* $data: the encoded data
*
* returns the decoded data
*/
function uudecode($data)
{
$d = explode("\n", $data);
$u = "";
for ($i = 0; $i < count($d) - 1; $i ++)
$u .= uudecode_line($d[$i]);
return $u;
}
/*
* returns the mimetype of an filename
*
* $name: the complete filename of a file
*
* returns a string containing the mimetype
*/
function get_mimetype_by_filename($name)
{
$ending = strtolower(strrchr($name, "."));
switch ($ending) {
case ".jpg":
case ".jpeg":
$type = "image/jpeg";
break;
case ".gif":
$type = "image/gif";
break;
case ".png":
$type = "image/png";
break;
case ".bmp":
$type = "image/bmp";
break;
default:
$type = "text/plain";
}
return $type;
}
function get_mimetype_by_string($filedata)
{
if (function_exists('finfo_open')) {
$f = finfo_open();
return finfo_buffer($f, $filedata, FILEINFO_MIME_TYPE);
} else {
return false;
}
}
/*
* Test, if the access to a group is allowed. This is true, if $testgroup is
* false or the groupname is in groups.txt
*
* $groupname: name of the group to be checked
*
* returns true, if access is allowed
*/
function testGroup($groupname)
{
global $CONFIG, $testgroup, $file_groups, $config_dir;
$groupname = strtolower($groupname);
if ($testgroup) {
$gf = fopen($file_groups, "r");
while (! feof($gf)) {
$read = trim(line_read($gf));
$read = preg_replace('/\t/', ' ', $read);
$read = strtolower($read);
$pos = strpos($read, " ");
if ($pos != false) {
if (substr($read, 0, $pos) == trim($groupname))
return true;
} else {
if ($read == trim($groupname))
return true;
}
}
fclose($gf);
if ($groupname == $CONFIG['spamgroup']) {
return true;
} else {
/* Find section */
$menulist = file($config_dir . "menu.conf", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
foreach ($menulist as $menu) {
if ($menu[0] == '#') {
continue;
}
$menuitem = explode(':', $menu);
if ($menuitem[1] == '0') {
continue;
}
$glfp = fopen($config_dir . $menuitem[0] . "/groups.txt", 'r');
$section = "";
while ($gl = fgets($glfp)) {
$group_name = preg_split("/( |\t)/", $gl, 2);
if (stripos(trim($groupname), trim($group_name[0])) !== false) {
fclose($glfp);
return true;
}
}
}
fclose($glfp);
return false;
}
} else {
return true;
}
}
function get_section_by_group($groupname)
{
global $CONFIG, $config_dir;
$menulist = file($config_dir . "menu.conf", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
// Get first group in Newsgroups
$groupname = preg_split("/( |\,)/", $groupname, 2);
$groupname = $groupname[0];
foreach ($menulist as $menu) {
if ($menu[0] == '#') {
continue;
}
$menuitem = explode(':', $menu);
if ($menuitem[1] == '0') {
continue;
}
$section = "";
$gldata = file($config_dir . $menuitem[0] . "/groups.txt");
foreach ($gldata as $gl) {
$group_name = preg_split("/( |\t)/", $gl, 2);
if (strtolower(trim($groupname)) == strtolower(trim($group_name[0]))) {
$section = $menuitem[0];
return $section;
}
}
}
return false;
}
function testGroups($newsgroups)
{
$groups = explode(",", $newsgroups);
$count = count($groups);
$return = "";
$o = 0;
for ($i = 0; $i < $count; $i ++) {
if (testgroup($groups[$i]) && (! function_exists("npreg_group_has_write_access") || npreg_group_has_write_access($groups[$i]))) {
if ($o > 0)
$return .= ",";
$o ++;
$return .= $groups[$i];
}
}
return ($return);
}
/*
* read one line from the NNTP-server
*/
function line_read(&$ns)
{
if ($ns != false) {
$t = str_replace("\n", "", str_replace("\r", "", fgets($ns, 1200)));
return $t;
}
}
/*
* Split an internet-address string into its parts. An address string could
* be for example:
* - user@host.domain (Realname)
* - "Realname" <user@host.domain>
* - user@host.domain
*
* The address will be split into user, host (incl. domain) and realname
*
* $adrstring: The string containing the address in internet format
* $defaulthost: The name of the host which should be returned if the
* address-string doesn't contain a hostname.
*
* returns an hash containing the fields "mailbox", "host" and "personal"
*/
function address_decode($adrstring, $defaulthost)
{
$parsestring = trim($adrstring);
$len = strlen($parsestring);
$at_pos = strpos($parsestring, '@'); // find @
$ka_pos = strpos($parsestring, "("); // find (
$kz_pos = strpos($parsestring, ')'); // find )
$ha_pos = strpos($parsestring, '<'); // find <
$hz_pos = strpos($parsestring, '>'); // find >
$space_pos = strpos($parsestring, ')'); // find ' '
$email = "";
$mailbox = "";
$host = "";
$personal = "";
if ($space_pos != false) {
if (($ka_pos != false) && ($kz_pos != false)) {
$personal = substr($parsestring, $ka_pos + 1, $kz_pos - $ka_pos - 1);
$email = trim(substr($parsestring, 0, $ka_pos - 1));
}
} else {
$email = $adrstring;
}
if (($ha_pos != false) && ($hz_pos != false)) {
$email = trim(substr($parsestring, $ha_pos + 1, $hz_pos - $ha_pos - 1));
$personal = substr($parsestring, 0, $ha_pos - 1);
}
if ($at_pos != false) {
$mailbox = substr($email, 0, strpos($email, '@'));
$host = substr($email, strpos($email, '@') + 1);
} else {
$mailbox = $email;
$host = $defaulthost;
}
$personal = trim($personal);
if (substr($personal, 0, 1) == '"')
$personal = substr($personal, 1);
if (substr($personal, strlen($personal) - 1, 1) == '"')
$personal = substr($personal, 0, strlen($personal) - 1);
$result["mailbox"] = trim($mailbox);
$result["host"] = trim($host);
if ($personal != "")
$result["personal"] = $personal;
$complete[] = $result;
return ($complete);
}
/*
* Read the groupnames from groups.txt, and get additional informations
* of the groups from the newsserver
*
* when load=0, returns cached group list
* when load=1, checks if the cache should be used, and returns nothing
* when force_reload=true, rebuilds group list cache
*/
function groups_read($server, $port, $load = 0, $force_reload = false)
{
global $gl_age, $file_groups, $spooldir, $config_name, $cache_index;
// is there a cached version, and is it actual enough?
$cachefile = $spooldir . '/' . $config_name . '-groups.dat';
// if cache is new enough, don't recreate it
clearstatcache(TRUE, $cachefile);
if (! $force_reload && $load == 1 && file_exists($cachefile) && (filemtime($cachefile) + $cache_index > time())) {
return;
}
if (! $force_reload && file_exists($cachefile) && $load == 0) {
// cached file exists and is new enough, so lets read it out.
$file = fopen($cachefile, "r");
$data = "";
while (! feof($file)) {
$data .= fgets($file, 1000);
}
fclose($file);
$newsgroups = unserialize($data);
} else {
// force a refresh of the group list
$ns = nntp_open($server, $port);
if ($ns == false)
return false;
// $gf=fopen($file_groups,"r");
$gfdata = file($file_groups);
// if we want to mark groups with new articles with colors, we will later
// need the format of the overview
$overviewformat = thread_overview_read($ns);
foreach ($gfdata as $gf) {
$gruppe = new newsgroupType();
$tmp = preg_replace('/\t/', ' ', trim($gf));
if (substr($tmp, 0, 1) == ":") {
$gruppe->text = substr($tmp, 1);
$newsgroups[] = $gruppe;
} elseif (strlen($tmp) > 0) {
// is there a description in groups.txt?
$gr = explode(" ", $tmp, 2);
if (isset($gr[1])) { // Yes
$gruppe->name = $gr[0];
$desc = $gr[1];
} else { // No
// no, get it from the newsserver.
$gruppe->name = $tmp;
if (is_file($spooldir . '/' . $tmp . '-title')) {
$response = file_get_contents($spooldir . '/' . $tmp . '-title');
$desc = strrchr($response, "\t");
} else {
$desc = "-";
}
}
if (strcmp($desc, "") == 0)
$desc = "-";
$gruppe->description = $desc;
fputs($ns, "GROUP " . $gruppe->name . "\r\n");
$t = explode(" ", line_read($ns));
if ($t[0] == "211")
$gruppe->count = $t[1];
else {
nntp_close($ns);
$ns = nntp_open($server, $port);
if ($ns == false)
return false;
fputs($ns, "GROUP " . $gruppe->name . "\r\n");
$t = explode(" ", line_read($ns));
if ($t[0] == "211")
$gruppe->count = $t[1];
else
continue;
}
// mark group with new articles with colors
if ($gl_age) {
fputs($ns, 'XOVER ' . $t[3] . "\r\n");
$tmp = explode(" ", line_read($ns));
if ($tmp[0] == "224") {
$tmp = line_read($ns);
if ($tmp != ".") {
$head = thread_overview_interpret($tmp, $overviewformat, $gruppe->name);
$tmp = line_read($ns);
$gruppe->age = $head->date;
}
}
}
if ((strcmp(trim($gruppe->name), "") != 0) && (substr($gruppe->name, 0, 1) != "#"))
$newsgroups[] = $gruppe;
}
}
nntp_close($ns);
// write the data to the cachefile
file_put_contents($cachefile, serialize($newsgroups));
}
if ($load == 0) {
return $newsgroups;
} else {
return;
}
}
function groups_show($gruppen)
{
global $gl_age, $frame, $spooldir, $logdir, $CONFIG, $spoolnews;
if ($gruppen == false)
return;
global $file_thread, $text_groups;
$logfile = $logdir . '/debug.log';
write_access_log();
$c = count($gruppen);
$acttype = "keins";
echo '<table class="np_groups_table" cellspacing="0"><tr class="np_thread_head"><td width="45px" class="np_thread_head">';
echo 'Latest</td><td style="text-align: center;">Newsgroup</td><td width="8%" class="np_thread_head">Messages</td><td width="20%" class="np_thread_head" >Last Message</td></tr>';
$subs = array();
$nonsubs = array();
$user = null;
if (isset($_COOKIE['mail_name'])) {
if ($userdata = get_user_mail_auth_data($_COOKIE['mail_name'])) {
$userfile = $spooldir . '/' . strtolower($_COOKIE['mail_name']) . '-articleviews.dat';
}
}
for ($i = 0; $i < $c; $i ++) {
unset($groupdisplay);
$g = $gruppen[$i];
if (isset($g->text)) {
if ($acttype != "text") {
$acttype = "text";
}
} else {
if ($acttype != "group") {
$acttype = "group";
}
/* Display group name and description */
if (isset($userdata[$g->name])) {
$lineclass = "np_thread_line2";
} else {
$lineclass = "np_thread_line1";
}
$groupdisplay = '<tr class="' . $lineclass . '"><td style="text-align: center;" class="' . $lineclass . '">';
$groupdisplay .= '<a href="overboard.php?thisgroup=' . _rawurlencode($g->name) . '">';
if (file_exists('../common/themes/' . $_SESSION['theme'] . '/images/latest.png')) {
$latest_image = '../common/themes/' . $_SESSION['theme'] . '/images/latest.png';
} else {
$latest_image = '../common/images/latest.png';
}
$groupdisplay .= '<img src="' . $latest_image . '">';
$groupdisplay .= '</a>';
$groupdisplay .= '</td>';
$groupdisplay .= '<td class="' . $lineclass . '">';
$groupdisplay .= '<span class="np_group_line_text">';
$groupdisplay .= '<a ';
$groupdisplay .= 'target="' . $frame['content'] . '" ';
$groupdisplay .= 'href="' . $file_thread . '?group=' . _rawurlencode($g->name) . '"><span class="np_group_line_text">' . group_display_name($g->name) . "</span></a>\n";
if ($g->description != "-")
$groupdisplay .= '</span><br><p class="np_group_desc">' . $g->description . '</p>';
// Subscribed features
$filename = $spooldir . "/" . $g->name . "-lastarticleinfo.dat";
if (is_file($filename)) {
$lastarticleinfo = unserialize(file_get_contents($filename));
} else {
$lastarticleinfo['date'] = 0;
}
// Look up last article info for group (np does not write this file sometimes for some reason)
$database = $spooldir . '/articles-overview.db3';
$table = 'overview';
$articles_dbh = overview_db_open($database);
$articles_query = $articles_dbh->prepare('SELECT * FROM overview WHERE newsgroup=:group ORDER BY date DESC LIMIT 2');
$articles_query->execute([
'group' => $g->name
]);
$found = 0;
while ($row = $articles_query->fetch()) {
$found = 1;
break;
}
$articles_dbh = null;
if ($found == 1) {
$lastarticleinfo['date'] = $row['date'];
}
if (isset($userdata[$g->name])) {
$groupdisplay .= '</span><p class="np_group_desc">';
$groupdisplay .= '<a class="np_group_desc" href="index.php?unsub=' . $g->name . '">(unsubscribe)</a>';
// TESTING HERE
/*
* file_put_contents($logfile, "\n".format_log_date()." ".$config_name." ".$g->name." is subscribed for ".$_COOKIE['mail_name'], FILE_APPEND);
* file_put_contents($logfile, "\n".format_log_date()." ".$config_name." userdata=".$userdata[$g->name]." <? lastarticleinfo=".$lastarticleinfo['date'], FILE_APPEND);
* file_put_contents($logfile, "\n".format_log_date()." ".$config_name." ".$g->name." ".($userdata[$g->name] - $lastarticleinfo['date']), FILE_APPEND);
*/
if ($userdata[$g->name] < $lastarticleinfo['date']) {
$groupdisplay .= '<a href="overboard.php?thisgroup=' . _rawurlencode($g->name) . '&time=' . $userdata[$g->name] . '"><b>(new)</b></a> ';
}
$groupdisplay .= '</p';
}
/* Display article count */
$groupdisplay .= '</td><td class="' . $lineclass . '">';
if ($gl_age)
$datecolor = thread_format_date_color($g->age);
$groupdisplay .= '<small>';
if ($datecolor != "")
$groupdisplay .= '<font color="' . $datecolor . '">' . $g->count . '</font>';
else
$groupdisplay .= $g->count;
$groupdisplay .= '</small>';
/* Display latest article info */
$groupdisplay .= '</td><td class="' . $lineclass . '"><div class="np_last_posted_date">';
if ($found == 1) {
// $lastarticleinfo['date'] = $row['date'];
// Put this in a function already!
$fromoutput = explode("<", html_entity_decode($row['name']));
// Just an email address?
if (strlen($fromoutput[0]) < 2) {
preg_match("/\<([^\)]*)\@/", html_entity_decode($row['name']), $fromaddress);
$fromoutput[0] = $fromaddress[1];
}
if (strpos($fromoutput[0], "(")) {
preg_match("/\(([^\)]*)\)/", html_entity_decode($row['name']), $fromaddress);
$fromoutput[0] = $fromaddress[1];
}
if ((isset($CONFIG['hide_email']) && $CONFIG['hide_email'] == true) && (strpos($fromoutput[0], '@') !== false)) {
$lastarticleinfo['name'] = truncate_email($fromoutput[0]);
} else {
$lastarticleinfo['name'] = $fromoutput[0];
}
}
$groupdisplay .= get_date_interval(date("D, j M Y H:i T", $lastarticleinfo['date']));
$groupdisplay .= '<table><tr><td>';
$groupdisplay .= '<font class="np_last_posted_date">by: ';
$groupdisplay .= create_name_link(mb_decode_mimeheader(html_entity_decode($lastarticleinfo['name'])), $lastarticleinfo['from']);
$groupdisplay .= '</td></tr></table>';
}
if (isset($groupdisplay)) {
$groupdisplay .= "\n";
flush();
if (isset($userdata[$g->name])) {
$subs[] = $groupdisplay;
} else {
$nonsubs[] = $groupdisplay;
}
}
} // END
foreach ($subs as $sub) {
echo $sub;
}
foreach ($nonsubs as $nonsub) {
echo $nonsub;
}
echo "</td></div></table>\n";
}
/*
* print the group names from an array to the webpage
*/
function groups_show_frames($gruppen)
{
global $gl_age, $frame, $spooldir;
if ($gruppen == false)
return;
global $file_thread, $text_groups;
$c = count($gruppen);
echo '<div class="np_index_groupblock">';
$acttype = "keins";
for ($i = 0; $i < $c; $i ++) {
$g = $gruppen[$i];
if (isset($g->text)) {
if ($acttype != "text") {
$acttype = "text";
if ($i > 0)
echo '</div>';
echo '<div class="np_index_grouphead">';
}
echo $g->text;
} else {
if ($acttype != "group") {
$acttype = "group";
if ($i > 0)
echo '</div>';
echo '<div class="np_index_groupblock">';
}
echo '<div class="np_index_group">';
echo '<b><a ';
echo 'target="' . $frame['content'] . '" ';
echo 'href="' . $file_thread . '?group=' . _rawurlencode($g->name) . '">' . group_display_name($g->name) . "</a></b>\n";
if ($gl_age)
$datecolor = thread_format_date_color($g->age);
echo '<small>(';
if ($datecolor != "")
echo '<font color="' . $datecolor . '">' . $g->count . '</font>';
else
echo $g->count;
echo ')</small>';
if ($g->description != "-")
echo '<br><small>' . $g->description . '</small>';
echo '</div>';
}
echo "\n";
flush();
}
echo "</div></div>\n";
}
/*
* gets a list of available articles in the group $groupname
*/
/*
* function getArticleList(&$ns,$groupname) {
* fputs($ns,"LISTGROUP $groupname \r\n");
* $line=line_read($ns);
* $line=line_read($ns);
* while(strcmp($line,".") != 0) {
* $articleList[] = trim($line);
* $line=line_read($ns);
* }
* if (!isset($articleList)) $articleList="-";
* return $articleList;
* }
*/
/*
* Decode quoted-printable or base64 encoded headerlines
*
* $value: The to be decoded line
*
* returns the decoded line
*/
function headerDecode($value)
{
return mb_decode_mimeheader($value);
}
/*
* calculates an Unix timestamp out of a Date-Header in an article
*
* $value: Value of the Date: header
*
* returns an Unix timestamp
*/
function getTimestamp($value)
{
global $CONFIG;
return strtotime($value);
}
function parse_header($hdr, $number = "")
{
for ($i = count($hdr) - 1; $i > 0; $i --)
if (preg_match("/^(\x09|\x20)/", $hdr[$i]))
$hdr[$i - 1] = $hdr[$i - 1] . " " . ltrim($hdr[$i]);
$header = new headerType();
$header->isAnswer = false;
for ($count = 0; $count < count($hdr); $count ++) {
$variable = substr($hdr[$count], 0, strpos($hdr[$count], " "));
$value = trim(substr($hdr[$count], strpos($hdr[$count], " ") + 1));
switch (strtolower($variable)) {
case "from:":
$fromline = address_decode(headerDecode($value), "nowhere");
if (! isset($fromline[0]["host"]))
$fromline[0]["host"] = "";
$header->from = $fromline[0]["mailbox"] . "@" . $fromline[0]["host"];
$header->username = $fromline[0]["mailbox"];
if (! isset($fromline[0]["personal"])) {
$header->name = "";
} else {
$header->name = $fromline[0]["personal"];
}
break;
case "message-id:":
$header->id = $value;
break;
case "subject:":
$header->subject = headerDecode($value);
break;
case "newsgroups:":
$header->newsgroups = $value;
break;
case "organization:":
$header->organization = headerDecode($value);
break;
case "content-transfer-encoding:":
$header->content_transfer_encoding = trim(strtolower($value));
break;
case "content-type:":
$header->content_type = array();
$subheader = explode(";", $value);
$header->content_type[0] = strtolower(trim($subheader[0]));
for ($i = 1; $i < count($subheader); $i ++) {
$gleichpos = strpos($subheader[$i], "=");
if ($gleichpos) {
$subvariable = trim(substr($subheader[$i], 0, $gleichpos));
$subvalue = trim(substr($subheader[$i], $gleichpos + 1));
if (($subvalue[0] == '"') && ($subvalue[strlen($subvalue) - 1] == '"'))
$subvalue = substr($subvalue, 1, strlen($subvalue) - 2);
switch ($subvariable) {
case "charset":
$header->content_type_charset = array(
strtolower($subvalue)
);
break;
case "name":
$header->content_type_name = array(
$subvalue
);
break;
case "boundary":
$header->content_type_boundary = $subvalue;
break;
case "format":
$header->content_type_format = array(
$subvalue
);
}
}
}
break;
case "references:":
$ref = trim($value);
while (strpos($ref, "> <") != false) {
$header->references[] = substr($ref, 0, strpos($ref, " "));
$ref = substr($ref, strpos($ref, "> <") + 2);
}
$header->references[] = trim($ref);
break;
case "date:":
$header->date = getTimestamp(trim($value));
break;
case "followup-to:":
$header->followup = trim($value);
break;
case "x-newsreader:":
case "x-mailer:":
case "x-rslight-to:":
$header->rslight_to = trim($value);
break;
case "x-rslight-site:":
$header->rslight_site = trim($value);
break;
case "user-agent:":
$header->user_agent = trim($value);
break;
case "x-face:": // not ready
// echo "<p>-".base64_decode($value)."-</p>";
break;
case "x-no-archive:":
$header->xnoarchive = strtolower(trim($value));
}
}
if (! isset($header->content_type[0]))
$header->content_type[0] = "text/plain";
if (! isset($header->content_transfer_encoding))
$header->content_transfer_encoding = "8bit";
if ($number != "")
$header->number = $number;
return $header;
}
/*
* convert the charset of a text
*/
function recode_charset($text, $source = false, $dest = false)
{
global $iconv_enable, $www_charset;
if ($dest == false)
$dest = $www_charset;
if (($iconv_enable) && ($source != false)) {
$return = iconv($source, $dest . "//TRANSLIT", $text);
if ($return != "")
return $return;
else
return $text;
} else {
return $text;
}
}
function decode_body($body, $encoding)
{
$bodyzeile = "";
switch ($encoding) {
case "base64":
$body = base64_decode($body);
break;
case "quoted-printable":
$body = Quoted_printable_decode($body);
$body = str_replace("=\n", "", $body);
// default:
// $body=str_replace("\n..\n","\n.\n",$body);
}
return $body;
}
/*
* makes URLs clickable
*
* $text: A text-line probably containing links.
*
* the function returns the text-line with HTML-Links to the links or
* email-adresses.
*/
function html_parse($text)
{
global $frame_externallink;
if ((isset($frame_externallink)) && ($frame_externallink != "")) {
$target = ' TARGET="' . $frame_externallink . '" ';
} else {
$target = ' ';
}
$ntext = "";
// split every line into it's words
$words = explode(" ", $text);
$n = count($words);
$is_link = 0;
for ($i = 0; $i < $n; $i ++) {
$word = $words[$i];
if (preg_match('/(https?|ftp|news|gopher|telnet)\:\/\/[^\",]+/i', $word)) {
$is_link = 1;
$nlink = trim($word, '().,');
$nlink = preg_replace('/(\&lt|\&gt|\&nbsp);/', '', $nlink);
$nlink = preg_replace('/\[url=/', '', $nlink);
$bbnlink = explode(']', $nlink);
$nlink = $bbnlink[0];
$nword = '<a ' . $target . ' href="' . $nlink . '">' . $nlink . '</a>';
if (isset($bbnlink[1])) {
$nword .= ' ' . $bbnlink[1];
}
if ($nword != $word && substr($nlink, strlen($nlink) - 3) != "://") {
$word = $nword;
}
}
// add the spaces between the words
if ($i > 0)
$ntext .= " ";
if ($is_link) {
$word = preg_replace('/\[\/url\]/', '', $word);
}
$ntext .= $word;
}
return ($ntext);
}
/*
* read the header of an article in plaintext into an array
* $articleNumber can be the number of an article or its message-id.
*/
function readPlainHeader(&$ns, $group, $articleNumber)
{
fputs($ns, "GROUP $group\r\n");
$line = line_read($ns);
fputs($ns, "HEAD $articleNumber\r\n");
$line = line_read($ns);
if (substr($line, 0, 3) != "221") {
echo $text_error["article_not_found"];
$header = false;
} else {
$line = line_read($ns);
$body = "";
while (strcmp(trim($line), ".") != 0) {
$body .= $line . "\n";
$line = line_read($ns);
}
return explode("\n", str_replace("\r\n", "\n", $body));
}
}
/*
* cancel an article on the newsserver
*
* DO NOT USE THIS FUNCTION, IF YOU DON'T KNOW WHAT YOU ARE DOING!
*
* $ns: The handler of the NNTP-Connection
* $group: The group of the article
* $id: the Number of the article inside the group or the message-id
*/
function message_cancel($subject, $from, $newsgroups, $ref, $body, $id)
{
global $server, $port, $send_poster_host, $CONFIG, $text_error;
global $www_charset;
flush();
$ns = nntp_open($server, $port);
if ($ns != false) {
fputs($ns, "POST\r\n");
$weg = line_read($ns);
fputs($ns, 'Subject: ' . quoted_printable_encode($subject) . "\r\n");
fputs($ns, 'From: ' . $from . "\r\n");
fputs($ns, 'Newsgroups: ' . $newsgroups . "\r\n");
fputs($ns, "Mime-Version: 1.0\r\n");
fputs($ns, "Content-Type: text/plain; charset=" . $www_charset . "\r\n");
fputs($ns, "Content-Transfer-Encoding: 8bit\r\n");
if ($send_poster_host)
fputs($ns, 'X-HTTP-Posting-Host: ' . gethostbyaddr(getenv("REMOTE_ADDR")) . "\r\n");
if ($ref != false)
fputs($ns, 'References: ' . $ref . "\r\n");
if (isset($CONFIG['organization']))
fputs($ns, 'Organization: ' . quoted_printable_encode($CONFIG['organization']) . "\r\n");
fputs($ns, "Control: cancel " . $id . "\r\n");
$body = str_replace("\n.\r", "\n..\r", $body);
$body = str_replace("\r", '', $body);
$b = explode("\n", $body);
$body = "";
for ($i = 0; $i < count($b); $i ++) {
if ((strpos(substr($b[$i], 0, strpos($b[$i], " ")), ">") != false) | (strcmp(substr($b[$i], 0, 1), ">") == 0)) {
$body .= textwrap(stripSlashes($b[$i]), 78, "\r\n") . "\r\n";
} else {
$body .= textwrap(stripSlashes($b[$i]), 74, "\r\n") . "\r\n";
}
}
fputs($ns, "\r\n" . $body . "\r\n.\r\n");
$message = line_read($ns);
nntp_close($ns);
} else {
$message = $text_error["post_failed"];
}
return $message;
}
function rslight_encrypt($data, $key)
{
$encryption_key = base64_decode($key);
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes-256-cbc'));
$encrypted = openssl_encrypt($data, 'aes-256-cbc', $encryption_key, 0, $iv);
return base64_encode($encrypted . '::' . $iv);
}
function _rawurlencode($string)
{
$string = rawurlencode(str_replace('+', '%2B', $string));
return $string;
}
function _rawurldecode($string)
{
$string = rawurldecode(str_replace('%2B', '+', $string));
return $string;
}
function rslight_decrypt($data, $key)
{
$encryption_key = base64_decode($key);
list ($encrypted_data, $iv) = explode('::', base64_decode($data), 2);
return openssl_decrypt($encrypted_data, 'aes-256-cbc', $encryption_key, 0, $iv);
}
function group_display_name($gname)
{
global $config_dir;
$namelist = file($config_dir . "rename.conf", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
foreach ($namelist as $name) {
if ($name[0] == '#') {
continue;
}
$nameitem = explode(':', $name);
if (! strcmp(trim($nameitem[0]), trim($gname))) {
return $nameitem[1];
}
}
return $gname;
}
function check_bbs_auth($username, $password)
{
global $config_dir, $CONFIG;
if ($username == '' && $password == '') {
return false;
}
$workpath = $config_dir . "users/";
$username = trim(strtolower($username));
$userFilename = $workpath . $username;
$keyFilename = $config_dir . "/userconfig/" . $username;
// Create accounts for $anonymous and $CONFIG['server_auth_user'] if not exist
if ($username == strtolower($CONFIG['anonusername'])) {
if (filemtime($config_dir . "rslight.inc.php") > filemtime($userFilename)) {
if ($userFileHandle = fopen($userFilename, 'w+')) {
fwrite($userFileHandle, password_hash($CONFIG['anonuserpass'], PASSWORD_DEFAULT));
fclose($userFileHandle);
}
}
}
if ($username == strtolower($CONFIG['server_auth_user'])) {
if (filemtime($config_dir . "rslight.inc.php") > filemtime($userFilename)) {
if ($userFileHandle = fopen($userFilename, 'w+')) {
fwrite($userFileHandle, password_hash($CONFIG['server_auth_pass'], PASSWORD_DEFAULT));
fclose($userFileHandle);
}
}
}
if (trim($username) == strtolower($CONFIG['anonusername']) && $CONFIG['anonuser'] != true) {
return FALSE;
}
if ($userFileHandle = fopen($userFilename, 'r')) {
$userFileInfo = fread($userFileHandle, filesize($userFilename));
fclose($userFileHandle);
if (password_verify($password, $userFileInfo)) {
touch($userFilename);
$ok = TRUE;
} else {
return FALSE;
}
} else {
$ok = FALSE;
}
if ($ok) {
return TRUE;
} else {
if (isset($CONFIG['auto_create']) && $CONFIG['auto_create'] == true) {
if ($userFileHandle = @fopen($userFilename, 'w+')) {
fwrite($userFileHandle, password_hash($password, PASSWORD_DEFAULT));
fclose($userFileHandle);
chmod($userFilename, 0666);
}
$newkey = base64_encode(openssl_random_pseudo_bytes(44));
if ($userFileHandle = @fopen($keyFilename, 'w+')) {
fwrite($userFileHandle, 'encryptionkey:' . $newkey);
fclose($userFileHandle);
chmod($userFilename, 0666);
}
return TRUE;
} else {
return FALSE;
}
}
}
function check_encryption_groups($request)
{
global $config_path;
$groupsFilename = $config_path . "encryption_ok.txt";
if ($groupsFileHandle = @fopen($groupsFilename, 'r')) {
while (! feof($groupsFileHandle)) {
$buffer = fgets($groupsFileHandle);
$buffer = str_replace(array(
"\r",
"\n"
), '', $buffer);
if (! strcmp($buffer, $request)) {
fclose($groupsFileHandle);
return TRUE;
}
}
fclose($groupsFileHandle);
} else {
return FALSE;
}
}
function set_user_config($username, $request, $newval)
{
global $config_dir;
$userconfigpath = $config_dir . "userconfig/";
$username = strtolower($username);
$userFilename = $userconfigpath . $username;
$userData = file($userFilename, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
$userFileHandle = fopen($userFilename, 'w');
$found = 0;
foreach ($userData as $data) {
if (strpos($data, $request . ':') !== FALSE) {
fputs($userFileHandle, $request . ':' . $newval . "\r\n");
$found = 1;
} else {
fputs($userFileHandle, $data . "\r\n");
}
}
if ($found == 0) {
fputs($userFileHandle, $request . ':' . $newval . "\r\n");
}
fclose($userFileHandle);
return;
}
function get_user_config($username, $request)
{
global $config_dir;
$userconfigpath = $config_dir . "userconfig/";
$username = strtolower($username);
$userFilename = $userconfigpath . $username;
if ($userFileHandle = @fopen($userFilename, 'r')) {
while (! feof($userFileHandle)) {
$buffer = fgets($userFileHandle);
if (strpos($buffer, $request . ':') !== FALSE) {
$userdataline = $buffer;
fclose($userFileHandle);
$userdatafound = explode(':', $userdataline);
return trim($userdatafound[1]);
}
}
fclose($userFileHandle);
return FALSE;
} else {
return FALSE;
}
}
function is_multibyte($s)
{
return mb_strlen($s, 'utf-8') < strlen($s);
}
function check_spam($subject, $from, $newsgroups, $ref, $body, $msgid)
{
global $msgid_generate, $msgid_fqdn, $spooldir;
global $CONFIG;
$spamfile = tempnam($spooldir, 'spam-');
$tmpheader = 'From: ' . $from . "\r\n";
if (strpos($from, $CONFIG['anonusername'])) {
$tmpheader .= "Anonymous: TRUE\r\n";
}
$tmpheader .= 'Message-ID: ' . $msgid . "\r\n";
$tmpheader .= 'Subject: ' . encode_subject($subject) . "\r\n\r\n";
if ($spamFileHandle = fopen($spamfile, 'w')) {
fwrite($spamFileHandle, $tmpheader);
fwrite($spamFileHandle, $body);
$spamcommand = $CONFIG['spamc'] . ' -E < ' . $spamfile;
ob_start();
$spamresult = passthru($spamcommand, $res);
$spamresult = ob_get_contents();
ob_end_clean();
$spam_fail = 1;
foreach (explode(PHP_EOL, $spamresult) as $line) {
$line = str_replace(array(
"\n\r",
"\n",
"\r"
), '', $line);
if (strpos($line, 'X-Spam-Checker-Version:') !== FALSE) {
$spamcheckerversion = $line;
$spam_fail = 0;
}
if (strpos($line, 'X-Spam-Level:') !== FALSE) {
$spamlevel = $line;
}
}
}
fclose($spamFileHandle);
unlink($spamfile);
return array(
'res' => $res,
'spamresult' => $spamresult,
'spamcheckerversion' => $spamcheckerversion,
'spamlevel' => $spamlevel,
'spam_fail' => $spam_fail
);
}
function format_log_date()
{
return date('M d H:i:s');
}
function create_name_link($name, $data = null)
{
global $CONFIG;
$name = preg_replace('/\"/', '', $name);
if ($data) {
$data = urlencode(base64_encode($data));
}
if ((strpos($name, '...@') !== false && (isset($CONFIG['hide_email']) && $CONFIG['hide_email'] == true)) && ! $data) {
$return = '<span class="visited">' . substr(htmlspecialchars($name), 0, 20) . '</span>';
} else {
$return = '<a href="search.php?command=search&searchpoint=Poster&terms=' . $name . '&data=' . $data . '"><span class="visited">' . substr(htmlspecialchars($name), 0, 20) . '</span></a>';
}
return ($return);
}
function truncate_email($address)
{
$before_at = explode('@', $address);
$namelen = strlen($before_at[0]);
if ($namelen > 3) {
$endname = $namelen - 3;
if ($endname > 8)
$endname = 8;
if ($endname < 3)
$endname ++;
if ($endname < 3)
$endname ++;
} else {
$endname = $namelen;
}
return substr($before_at[0], 0, $endname) . '...' . substr($address, $namelen, strlen($address));
}
function get_date_interval($value)
{
$current = time();
$datetime1 = date_create($value);
$datetime2 = date_create("@$current");
$interval = date_diff($datetime1, $datetime2);
if (! $interval) {
return '(date error)';
}
$years = $interval->format('%y') . " Years ";
$months = $interval->format('%m') . " Months ";
$days = $interval->format('%d') . " Days ";
$hours = $interval->format('%h') . " Hours ";
$minutes = $interval->format('%i') . " Minutes ";
if ($interval->format('%y') == 1) {
$years = $interval->format('%y') . " Year ";
}
if ($interval->format('%m') == 1) {
$months = $interval->format('%m') . " Month ";
}
if ($interval->format('%d') == 1) {
$days = $interval->format('%d') . " Day ";
}
if ($interval->format('%h') == 1) {
$hours = $interval->format('%h') . " Hour ";
}
if ($interval->format('%i') == 1) {
$minutes = $interval->format('%i') . " Minute ";
}
if ($interval->format('%y') == 0) {
$years = '';
}
if ($interval->format('%m') == 0) {
$months = '';
}
if ($interval->format('%d') == 0) {
$days = '';
}
if ($interval->format('%h') == 0) {
$hours = '';
}
if ($interval->format('%i') == 0) {
$minutes = '';
}
if ($years > 0) {
$days = '';
$hours = '';
$minutes = '';
}
if ($months > 0) {
$hours = '';
$minutes = '';
}
if ($days > 0) {
$minutes = '';
}
$variance = $interval->format($years . $months . $days . $hours . $minutes . ' ago');
if (strlen($variance) < 5) {
$variance = " now";
}
return $variance;
}
function get_search_snippet($body, $content_type = '')
{
$body = quoted_printable_decode($body);
if ($content_type !== '') {
$mysnippet = recode_charset($body, $content_type, "utf8");
} else {
$mysnippet = $body;
}
if ($bodyend = strrpos($mysnippet, "\n---\n")) {
$mysnippet = substr($mysnippet, 0, $bodyend);
} else {
if ($bodyend = strrpos($mysnippet, "\n-- ")) {
$mysnippet = substr($mysnippet, 0, $bodyend);
} else {
if ($bodyend = strrpos($mysnippet, "\n.")) {
$mysnippet = substr($mysnippet, 0, $bodyend);
}
}
}
$mysnippet = preg_replace('/\n.{0,5}>(.*)/', '', $mysnippet);
$snipstart = strpos($mysnippet, ":\n");
if (substr_count(trim(substr($mysnippet, 0, $snipstart)), "\n") < 2) {
$mysnippet = substr($mysnippet, $snipstart + 1);
} else {
$mysnippet = substr($mysnippet, 0);
}
return $mysnippet;
}
function mail_db_open($database, $table = 'messages')
{
try {
$dbh = new PDO('sqlite:' . $database);
} catch (PDOException $e) {
echo 'Connection failed: ' . $e->getMessage();
exit();
}
$dbh->exec("CREATE TABLE IF NOT EXISTS messages(
id INTEGER PRIMARY KEY,
msgid TEXT UNIQUE,
mail_from TEXT,
mail_viewed TEXT,
rcpt_to TEXT,
rcpt_viewed TEXT,
rcpt_target TEXT,
date TEXT,
subject TEXT,
message TEXT,
from_hide TEXT,
to_hide TEXT)");
return ($dbh);
}
function history_db_open($database, $table = 'history')
{
try {
$dbh = new PDO('sqlite:' . $database);
} catch (PDOException $e) {
echo 'Connection failed: ' . $e->getMessage();
exit();
}
$dbh->exec("CREATE TABLE IF NOT EXISTS $table(
id INTEGER PRIMARY KEY,
newsgroup TEXT,
number TEXT,
msgid TEXT,
status TEXT,
statusdate TEXT,
statusreason TEXT,
statusnotes TEXT,
unique (newsgroup, msgid),
unique (newsgroup, number))");
$stmt = $dbh->query('CREATE INDEX IF NOT EXISTS id_status on ' . $table . '(status)');
$stmt->execute();
$stmt = $dbh->query('CREATE INDEX IF NOT EXISTS id_newsgroup on ' . $table . '(newsgroup)');
$stmt->execute();
$stmt = $dbh->query('CREATE INDEX IF NOT EXISTS id_msgid on ' . $table . '(msgid)');
$stmt->execute();
$stmt = $dbh->query('CREATE INDEX IF NOT EXISTS id_newsgroup_number on ' . $table . '(newsgroup,number)');
$stmt->execute();
$stmt = $dbh->query('CREATE INDEX IF NOT EXISTS id_statusdate on ' . $table . '(statusdate)');
$stmt->execute();
return ($dbh);
}
function overview_db_open($database, $table = 'overview')
{
try {
$dbh = new PDO('sqlite:' . $database);
} catch (PDOException $e) {
echo 'Connection failed: ' . $e->getMessage();
exit();
}
$dbh->exec("CREATE TABLE IF NOT EXISTS $table(
id INTEGER PRIMARY KEY,
newsgroup TEXT,
number TEXT,
msgid TEXT,
date TEXT,
datestring TEXT,
name TEXT,
subject TEXT,
refs TEXT,
bytes TEXT,
lines TEXT,
xref TEXT,
unique (newsgroup, msgid))");
$stmt = $dbh->query('CREATE INDEX IF NOT EXISTS id_date on ' . $table . '(date)');
$stmt->execute();
$stmt = $dbh->query('CREATE INDEX IF NOT EXISTS id_newsgroup on ' . $table . '(newsgroup)');
$stmt->execute();
$stmt = $dbh->query('CREATE INDEX IF NOT EXISTS id_msgid on ' . $table . '(msgid)');
$stmt->execute();
$stmt = $dbh->query('CREATE INDEX IF NOT EXISTS id_newsgroup_number on ' . $table . '(newsgroup,number)');
$stmt->execute();
$stmt = $dbh->query('CREATE INDEX IF NOT EXISTS id_name on ' . $table . '(name)');
$stmt->execute();
return ($dbh);
}
function article_db_open($database, $table = 'articles')
{
try {
$dbh = new PDO('sqlite:' . $database);
} catch (PDOException $e) {
echo 'Connection failed: ' . $e->getMessage();
exit();
}
$dbh->exec("CREATE TABLE IF NOT EXISTS $table(
id INTEGER PRIMARY KEY,
newsgroup TEXT,
number TEXT UNIQUE,
msgid TEXT UNIQUE,
date TEXT,
name TEXT,
subject TEXT,
search_snippet TEXT,
article TEXT)");
$stmt = $dbh->query('CREATE INDEX IF NOT EXISTS db_number on ' . $table . '(number)');
$stmt->execute();
$stmt = $dbh->query('CREATE INDEX IF NOT EXISTS db_date on ' . $table . '(date)');
$stmt->execute();
$stmt = $dbh->query('CREATE INDEX IF NOT EXISTS db_msgid on ' . $table . '(msgid)');
$stmt->execute();
$stmt = $dbh->query('CREATE INDEX IF NOT EXISTS db_name on ' . $table . '(name)');
$stmt->execute();
$dbh->exec("CREATE VIRTUAL TABLE IF NOT EXISTS search_fts USING fts5(
newsgroup,
number,
msgid,
date,
name,
subject,
search_snippet)");
$dbh->exec("CREATE TRIGGER IF NOT EXISTS after_articles_insert AFTER INSERT ON $table BEGIN
INSERT INTO search_fts(newsgroup, number, msgid, date, name, subject, search_snippet) VALUES(new.newsgroup, new.number, new.msgid, new.date, new.name, new.subject, new.search_snippet);
END;");
$dbh->exec("CREATE TRIGGER IF NOT EXISTS after_articles_delete AFTER DELETE ON $table BEGIN
DELETE FROM search_fts WHERE msgid = old.msgid;
END;");
return ($dbh);
}
function np_get_db_article($article, $group, $makearray = 1, $dbh = null)
{
global $config_dir, $path, $groupconfig, $config_name, $logdir, $spooldir;
$logfile = $logdir . '/newsportal.log';
$msg2 = "";
$closeme = 0;
$database = $spooldir . '/' . $group . '-articles.db3';
if (! $dbh) {
if (! is_file($database)) {
return FALSE;
}
$dbh = article_db_open($database);
$closeme = 1;
}
$ok_article = 0;
// By Message-ID
if (! is_numeric($article)) {
$stmt = $dbh->prepare("SELECT * FROM articles WHERE msgid like :terms");
$stmt->bindParam(':terms', $article);
$stmt->execute();
while ($found = $stmt->fetch()) {
$msg2 = $found['article'];
$ok_article = 1;
break;
}
} else {
$stmt = $dbh->prepare("SELECT * FROM articles WHERE number = :terms");
$stmt->bindParam(':terms', $article);
$stmt->execute();
while ($found = $stmt->fetch()) {
$msg2 = $found['article'];
$ok_article = 1;
break;
}
}
if ($closeme == 1) {
$dbh = null;
}
if ($ok_article !== 1) {
// file_put_contents($logfile, "\n".format_log_date()." ".$config_name." DEBUG: ".$article." from ".$group." not found in database", FILE_APPEND);
return FALSE;
}
// file_put_contents($logfile, "\n".format_log_date()." ".$config_name." DEBUG: fetched: ".$article." from ".$group, FILE_APPEND);
if ($makearray == 1) {
$thisarticle = preg_split("/\r\n|\n|\r/", trim($msg2));
array_pop($thisarticle);
return $thisarticle;
} else {
return trim($msg2);
}
}
function get_poster_name($name)
{
$fromline = address_decode($name, "nowhere");
if (! isset($fromline[0]["host"]))
$fromline[0]["host"] = "";
$name_from = $fromline[0]["mailbox"] . "@" . $fromline[0]["host"];
$name_username = $fromline[0]["mailbox"];
if (! isset($fromline[0]["personal"])) {
$poster_name = $fromline[0]["mailbox"];
} else {
$poster_name = $fromline[0]["personal"];
}
if (trim($poster_name) == '') {
$fromoutput = explode("<", html_entity_decode($name));
if (strlen($fromoutput[0]) < 1) {
$poster_name = $fromoutput[1];
} else {
$poster_name = $fromoutput[0];
}
}
$thisposter['name'] = $poster_name;
$thisposter['from'] = $name_from;
return ($thisposter);
}
function get_config_value($configfile, $request)
{
global $config_dir;
if ($configFileHandle = @fopen($config_dir . '/' . $configfile, 'r')) {
while (! feof($configFileHandle)) {
$buffer = fgets($configFileHandle);
if (strpos($buffer, $request . ':') !== FALSE) {
$dataline = $buffer;
fclose($configFileHandle);
$datafound = explode(':', $dataline);
return $datafound[1];
}
}
fclose($configFileHandle);
return FALSE;
} else {
return FALSE;
}
}
function throttle_hits()
{
global $CONFIG, $logdir;
$logfile = $logdir . '/newsportal.log';
if (! isset($_SESSION['starttime'])) {
$_SESSION['starttime'] = time();
$_SESSION['views'] = 0;
}
$_SESSION['views'] ++;
// $loadrate = allowed article request per second
$loadrate = .15;
$rate = fdiv($_SESSION['views'], (time() - $_SESSION['starttime']));
if (($rate > $loadrate) && ($_SESSION['views'] > 50)) {
header("HTTP/1.0 429 Too Many Requests");
if (! isset($_SESSION['throttled'])) {
file_put_contents($logfile, "\n" . format_log_date() . " " . $config_name . " Too many requests from " . $_SERVER['REMOTE_ADDR'] . " throttling", FILE_APPEND);
$_SESSION['throttled'] = true;
if (isset($_SESSION['rsactive'])) {
unset($_SESSION['rsactive']);
}
}
exit(0);
}
}
function get_user_mail_auth_data($user)
{
global $spooldir;
$userdata = array();
$user = strtolower($user);
$pkey_config = get_user_config($user, "pkey");
if (! isset($_COOKIE['pkey'])) {
$_COOKIE['pkey'] = null;
}
$pkey_cookie = $_COOKIE['pkey'];
if ((! isset($_COOKIE['pkey'])) || $pkey_config == false || $pkey_cookie == false) {
return false;
}
if ($pkey_config == $pkey_cookie) {
$userfile = $spooldir . '/' . $user . '-articleviews.dat';
if (is_file($userfile)) {
$userdata = unserialize(file_get_contents($userfile));
}
return $userdata;
}
return false;
}
function write_access_log()
{
global $logdir;
$accessfile = $logdir . '/access.log';
$currentPageUrl = $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"];
file_put_contents($accessfile, "\n" . format_log_date() . " " . $currentPageUrl, FILE_APPEND);
}
function verify_gpg_signature($res, $signed_text)
{
$result = gnupg_verify($res, $signed_text, false);
if ($result == false) {
return false;
}
if ((($result[0]['summary'] > 3)) || $result[0]['validity'] == 2) {
return false; // Bad signature
} else {
return true; // Good signature
}
}
function is_deleted_post($group, $number)
{
global $spooldir;
$database = $spooldir . '/history.db3';
$table = 'history';
$dbh = history_db_open($database, $table);
$stmt = $dbh->prepare("SELECT * FROM $table WHERE newsgroup=:newsgroup AND number=:nicole");
$stmt->bindParam(':newsgroup', $group);
$stmt->bindParam(':nicole', $number);
$stmt->execute();
$status = false;
while ($row = $stmt->fetch()) {
if ($row['status'] == "deleted") {
$status = "430 Article Deleted";
break;
}
}
$dbh = null;
return $status;
}
function add_to_history($group, $number, $msgid, $status, $statusdate, $statusreason = null, $statusnotes = null)
{
global $spooldir;
$history = $spooldir . '/history.db3';
$history_dbh = history_db_open($history);
$history_sql = 'INSERT OR IGNORE INTO history(newsgroup, number, msgid, status, statusdate, statusreason, statusnotes) VALUES(?,?,?,?,?,?,?)';
$history_stmt = $history_dbh->prepare($history_sql);
$history_stmt->execute([
$group,
$number,
$msgid,
$status,
$statusdate,
$statusreason,
$statusnotes
]);
$history_dbh = null;
}
function get_db_data_from_msgid($msgid, $group)
{
global $spooldir;
$database = $spooldir . '/' . $group . '-articles.db3';
if (! is_file($database)) {
return false;
}
$articles_dbh = article_db_open($database);
$articles_query = $articles_dbh->prepare('SELECT * FROM articles WHERE msgid=:messageid');
$articles_query->execute([
'messageid' => $msgid
]);
$found = 0;
while ($row = $articles_query->fetch()) {
$found = 1;
break;
}
$dbh = null;
if ($found) {
return $row;
} else {
return false;
}
}
function get_data_from_msgid($msgid)
{
global $spooldir;
$database = $spooldir . '/articles-overview.db3';
$articles_dbh = overview_db_open($database);
$articles_query = $articles_dbh->prepare('SELECT * FROM overview WHERE msgid=:messageid');
$articles_query->execute([
'messageid' => $msgid
]);
$found = 0;
while ($row = $articles_query->fetch()) {
$found = 1;
break;
}
$dbh = null;
if ($found) {
return $row;
} else {
return false;
}
}
function prune_dir_by_days($path, $days)
{
if ($filenames = array_diff(scandir($path), array(
'..',
'.'
))) {
foreach ($filenames as $file) {
$filelastmodified = filemtime($path . $file);
if ((time() - $filelastmodified) > $days * 86400) {
if (is_file($path . $file)) {
unlink($path . $file);
}
}
}
} else {
return false;
}
return true;
}
function send_admin_message($admin, $from, $subject, $message)
{
global $config_dir, $spooldir;
if (($to = get_config_value('aliases.conf', strtolower($admin))) == false) {
$to = strtolower($admin);
}
$to = trim($to);
$from = $to;
$database = $spooldir . '/mail.db3';
$dbh = mail_db_open($database);
if (! $dbh) {
echo "Database error\n";
return false;
}
$date = time();
$msgid = '<' . md5(strtolower($to) . strtolower($from) . strtolower($subject) . strtolower($message)) . '>';
$sql = 'INSERT OR IGNORE INTO messages(msgid, mail_from, rcpt_to, rcpt_target, date, subject, message, from_hide, to_hide, mail_viewed, rcpt_viewed) VALUES(?,?,?,?,?,?,?,?,?,?,?)';
$stmt = $dbh->prepare($sql);
$target = "local";
$mail_viewed = "true";
$rcpt_viewed = null;
$q = $stmt->execute([
$msgid,
$from,
$to,
$target,
$date,
$subject,
$message,
null,
null,
false,
false
]);
$dbh = null;
return true;
}