2020-11-29 01:55:31 +01:00
< ? php
2023-08-20 00:33:05 +02:00
/*
2023-09-06 13:07:57 +02:00
* NNTP <-> HTTP Gateway
* Download : https :// news . novabbs . com / get
2020-11-29 01:55:31 +01:00
*
2023-08-20 00:33:05 +02:00
* Based on Newsportal by Florian Amrhein
2020-11-29 01:55:31 +01:00
*
2023-08-20 00:33:05 +02:00
* E - Mail : retroguy @ novabbs . com
* Web : https :// news . novabbs . com
2020-11-29 01:55:31 +01:00
*
2023-08-20 00:33:05 +02:00
* 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 .
2020-11-29 01:55:31 +01:00
*
2023-08-20 00:33:05 +02:00
* 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 .
2020-11-29 01:55:31 +01:00
*
2023-08-20 00:33:05 +02:00
* 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
2020-11-29 01:55:31 +01:00
*/
2023-08-20 00:33:05 +02:00
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 " ;
2020-11-29 01:55:31 +01:00
2023-08-20 00:33:05 +02:00
$CONFIG = include ( $config_file );
2020-11-29 01:55:31 +01:00
/*
* opens the connection to the NNTP - Server
*
* $server : adress of the NNTP - Server
* $port : port of the server
*/
2023-08-20 00:33:05 +02:00
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>' ;
2024-01-02 13:16:53 +01:00
return false ;
2024-02-02 18:20:37 +01:00
// exit(0);
2023-08-20 00:33:05 +02:00
}
$weg = line_read ( $ns ); // kill the first line
if ( substr ( $weg , 0 , 2 ) != " 20 " ) {
echo " <p> " . $text_error [ " error: " ] . $weg . " </p> " ;
2020-11-29 01:55:31 +01:00
fclose ( $ns );
2023-08-20 00:33:05 +02:00
$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 ;
2020-11-29 01:55:31 +01:00
}
2023-08-20 00:33:05 +02:00
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);
2021-01-28 01:17:50 +01:00
} else {
2023-08-20 00:33:05 +02:00
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);
2023-10-24 04:01:30 +02:00
// echo "PORT: ".$nport." ns: ".$ns;
2023-08-20 00:33:05 +02:00
$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 ;
2021-01-28 01:17:50 +01:00
}
function fsocks4asockopen ( $proxyHostname , $proxyPort , $targetHostname , $targetPort )
{
$sock = fsockopen ( $proxyHostname , $proxyPort );
2023-08-20 00:33:05 +02:00
if ( $sock === false )
2021-01-28 01:17:50 +01:00
return false ;
2023-08-20 00:33:05 +02:00
fwrite ( $sock , pack ( " CCnCCCCC " , 0x04 , 0x01 , $targetPort , 0x00 , 0x00 , 0x00 , 0x01 , 0x00 ) . $targetHostname . pack ( " C " , 0x00 ));
2021-01-28 01:17:50 +01:00
$response = fread ( $sock , 16 );
$values = unpack ( " xnull/Cret/nport/Nip " , $response );
2023-08-20 00:33:05 +02:00
if ( $values [ " ret " ] == 0x5a )
return $sock ;
else {
2021-02-07 01:05:26 +01:00
fclose ( $sock );
2021-01-28 01:17:50 +01:00
return false ;
}
}
2020-11-29 01:55:31 +01:00
/*
* Close a NNTP connection
*
* $ns : the handle of the connection
*/
2023-08-20 00:33:05 +02:00
function nntp_close ( & $ns )
{
if ( $ns != false ) {
fputs ( $ns , " QUIT \r \n " );
fclose ( $ns );
}
2020-11-29 01:55:31 +01:00
}
/*
* 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 )
{
2023-08-20 00:33:05 +02:00
global $validate_email ;
$return = true ;
if (( $validate_email >= 1 ) && ( $return == true ))
2020-11-29 01:55:31 +01:00
/* 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 ;
2023-08-20 00:33:05 +02:00
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 );
2020-11-29 01:55:31 +01:00
}
/*
* decodes a block of 7 bit - data in uuencoded format to it ' s original
* 8 bit format .
* The headerline containing filename and permissions doesn ' t have to
* be included .
2023-08-20 00:33:05 +02:00
*
2020-11-29 01:55:31 +01:00
* $data : The uuencoded data as a string
*
* returns the 8 bit data as a string
*
* Note : this function is very slow and doesn ' t recognize incorrect code .
*/
2023-08-20 00:33:05 +02:00
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 ;
2020-11-29 01:55:31 +01:00
}
/*
* decodes uuencoded Attachments .
*
* $data : the encoded data
*
* returns the decoded data
*/
2023-08-20 00:33:05 +02:00
function uudecode ( $data )
{
$d = explode ( " \n " , $data );
$u = " " ;
for ( $i = 0 ; $i < count ( $d ) - 1 ; $i ++ )
$u .= uudecode_line ( $d [ $i ]);
return $u ;
2020-11-29 01:55:31 +01:00
}
/*
* returns the mimetype of an filename
*
* $name : the complete filename of a file
*
* returns a string containing the mimetype
*/
2023-08-20 00:33:05 +02:00
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 ;
2020-11-29 01:55:31 +01:00
}
2023-08-20 00:33:05 +02:00
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 ;
}
2020-11-29 01:55:31 +01:00
}
/*
* 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
*/
2023-08-20 00:33:05 +02:00
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 ;
}
2021-04-02 03:36:14 +02:00
}
2023-08-20 00:33:05 +02:00
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 ;
2021-04-02 03:36:14 +02:00
}
2020-11-29 01:55:31 +01:00
}
2023-08-20 00:33:05 +02:00
function get_section_by_group ( $groupname )
{
2021-04-02 08:23:14 +02:00
global $CONFIG , $config_dir ;
2023-08-20 00:33:05 +02:00
$menulist = file ( $config_dir . " menu.conf " , FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES );
// Get first group in Newsgroups
2022-07-24 22:33:45 +02:00
$groupname = preg_split ( " /( | \ ,)/ " , $groupname , 2 );
$groupname = $groupname [ 0 ];
2023-08-20 00:33:05 +02:00
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 ;
}
2021-04-02 08:23:14 +02:00
}
}
return false ;
}
2023-08-20 00:33:05 +02:00
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 );
2020-11-29 01:55:31 +01:00
}
/*
* read one line from the NNTP - server
*/
2023-08-20 00:33:05 +02:00
function line_read ( & $ns )
{
if ( $ns != false ) {
$t = str_replace ( " \n " , " " , str_replace ( " \r " , " " , fgets ( $ns , 1200 )));
return $t ;
}
2020-11-29 01:55:31 +01:00
}
/*
* 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
2023-08-20 00:33:05 +02:00
* address - string doesn ' t contain a hostname .
2020-11-29 01:55:31 +01:00
*
* returns an hash containing the fields " mailbox " , " host " and " personal "
*/
2023-08-20 00:33:05 +02:00
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 );
2020-11-29 01:55:31 +01:00
}
/*
* Read the groupnames from groups . txt , and get additional informations
* of the groups from the newsserver
2023-07-03 06:14:28 +02:00
*
* 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
2023-08-20 00:33:05 +02:00
*/
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 );
2020-11-29 01:55:31 +01:00
}
2023-08-20 00:33:05 +02:00
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 ;
2020-11-29 01:55:31 +01:00
}
}
2023-08-20 00:33:05 +02:00
nntp_close ( $ns );
// write the data to the cachefile
file_put_contents ( $cachefile , serialize ( $newsgroups ));
2023-08-14 15:37:08 +02:00
}
2023-08-20 00:33:05 +02:00
if ( $load == 0 ) {
return $newsgroups ;
} else {
return ;
2023-08-14 15:37:08 +02:00
}
2023-08-20 00:33:05 +02:00
}
function groups_show ( $gruppen )
{
2024-03-04 17:47:34 +01:00
global $gl_age , $frame , $spooldir , $config_dir , $logdir , $CONFIG , $OVERRIDES , $spoolnews ;
2023-08-20 00:33:05 +02:00
if ( $gruppen == false )
return ;
global $file_thread , $text_groups ;
$logfile = $logdir . '/debug.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 ;
2024-03-04 17:47:34 +01:00
// Get registered user settings
2023-08-20 00:33:05 +02:00
if ( isset ( $_COOKIE [ 'mail_name' ])) {
if ( $userdata = get_user_mail_auth_data ( $_COOKIE [ 'mail_name' ])) {
$userfile = $spooldir . '/' . strtolower ( $_COOKIE [ 'mail_name' ]) . '-articleviews.dat' ;
2024-03-04 17:47:34 +01:00
$user_config = unserialize ( file_get_contents ( $config_dir . '/userconfig/' . strtolower ( $_COOKIE [ 'mail_name' ]) . '.config' ));
}
if ( ! isset ( $user_config [ 'hide_unsub' ])) {
if ( isset ( $OVERRIDES [ 'hide_unsub' ])) {
$user_config [ 'hide_unsub' ] = $OVERRIDES [ 'hide_unsub' ];
} else {
$user_config [ 'hide_unsub' ] = 'hide' ;
}
2021-12-17 07:15:06 +01:00
}
2023-08-20 00:33:05 +02:00
}
for ( $i = 0 ; $i < $c ; $i ++ ) {
unset ( $groupdisplay );
$g = $gruppen [ $i ];
if ( isset ( $g -> text )) {
if ( $acttype != " text " ) {
$acttype = " text " ;
}
2021-12-17 07:15:06 +01:00
} else {
2023-08-20 00:33:05 +02:00
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 ) . '">' ;
2023-09-09 13:34:17 +02:00
if (( isset ( $_SESSION [ 'theme' ])) && file_exists ( '../common/themes/' . $_SESSION [ 'theme' ] . '/images/latest.png' )) {
2023-08-20 00:33:05 +02:00
$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' ] . '" ' ;
2023-09-19 12:06:57 +02:00
// Get last article info from overview
$database = $spooldir . '/articles-overview.db3' ;
$table = 'overview' ;
$overview_dbh = overview_db_open ( $database );
2024-03-31 20:14:43 +02:00
$overview_query = $overview_dbh -> prepare ( 'SELECT * FROM overview WHERE newsgroup=:newsgroup ORDER BY CAST(date AS int) DESC LIMIT 2' );
2023-09-19 12:06:57 +02:00
$overview_query -> execute ([
'newsgroup' => $g -> name
]);
2023-08-23 21:50:56 +02:00
$found = 0 ;
2023-09-19 12:06:57 +02:00
while ( $row = $overview_query -> fetch ()) {
2023-08-23 21:50:56 +02:00
$found = 1 ;
break ;
2023-08-20 00:33:05 +02:00
}
2023-08-23 21:50:56 +02:00
if ( $found == 1 ) {
$lastarticleinfo [ 'date' ] = $row [ 'date' ];
2023-08-20 00:33:05 +02:00
}
2023-10-03 04:16:48 +02:00
$new = false ;
$new_style_on = '' ;
$new_style_off = '' ;
if ( isset ( $userdata [ $g -> name ]) && ( $userdata [ $g -> name ] < $lastarticleinfo [ 'date' ])) {
$new_style_on = '<b><i>*' ;
$new_style_off = '</i></b>' ;
$new = true ;
}
2024-01-07 23:52:50 +01:00
$groupdisplay .= 'href="' . $file_thread . '?group=' . urlencode ( $g -> name ) . '"><span class="np_group_line_text">' . $new_style_on . group_display_name ( $g -> name ) . $new_style_off . " </span></a> \n " ;
2023-10-03 04:16:48 +02:00
if ( $new ) {
echo '</i></b>' ;
}
if ( $g -> description != " - " ) {
$groupdisplay .= '</span><br><p class="np_group_desc">' . $g -> description . '</p>' ;
}
2023-09-19 12:06:57 +02:00
$overview_dbh = null ;
2023-08-20 00:33:05 +02:00
if ( isset ( $userdata [ $g -> name ])) {
2023-09-19 15:39:01 +02:00
$groupdisplay .= '</span><p class="np_group_user_tools">' ;
2024-01-07 23:52:50 +01:00
$groupdisplay .= '<a class="np_group_user_tools" href="index.php?unsub=' . urlencode ( $g -> name ) . '">(unsubscribe)</a>' ;
2023-10-03 04:16:48 +02:00
if ( $new ) {
2024-01-07 23:52:50 +01:00
$groupdisplay .= ' <a href="overboard.php?thisgroup=' . urlencode ( $g -> name ) . '&time=' . $userdata [ $g -> name ] . '"><b>(new)</b></a> ' ;
2023-08-20 00:33:05 +02:00
}
$groupdisplay .= '</p' ;
2024-03-04 17:47:34 +01:00
} else {
if ( isset ( $user_config [ 'hide_unsub' ]) && $user_config [ 'hide_unsub' ] == 'hide' ) {
continue ;
}
2023-08-20 00:33:05 +02:00
}
/* 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 ) {
2023-08-26 14:48:13 +02:00
$poster = address_decode ( $row [ 'name' ], " nowhere " );
$lastarticleinfo [ 'from' ] = $poster [ 0 ][ 'mailbox' ] . " @ " . $poster [ 0 ][ 'host' ];
2023-09-08 14:09:37 +02:00
if ( isset ( $poster [ 0 ][ 'personal' ])) {
2023-08-26 14:48:13 +02:00
$lastarticleinfo [ 'name' ] = $poster [ 0 ][ 'personal' ];
2023-08-20 00:33:05 +02:00
} else {
2023-08-26 14:48:13 +02:00
$lastarticleinfo [ 'name' ] = $poster [ 0 ][ 'mailbox' ];
2023-08-20 00:33:05 +02:00
}
2023-08-26 14:48:13 +02:00
$fromoutput [ 0 ] = $poster [ 0 ][ 'mailbox' ] . " @ " . $poster [ 0 ][ 'host' ];
2024-01-29 13:33:12 +01:00
$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>' ;
} else {
unset ( $lastarticleinfo );
2023-08-20 00:33:05 +02:00
}
2021-12-17 07:15:06 +01:00
}
2023-08-20 00:33:05 +02:00
if ( isset ( $groupdisplay )) {
$groupdisplay .= " \n " ;
flush ();
if ( isset ( $userdata [ $g -> name ])) {
$subs [] = $groupdisplay ;
} else {
$nonsubs [] = $groupdisplay ;
}
}
2023-08-26 14:48:13 +02:00
}
2023-08-20 00:33:05 +02:00
foreach ( $subs as $sub ) {
echo $sub ;
}
foreach ( $nonsubs as $nonsub ) {
echo $nonsub ;
}
echo " </td></div></table> \n " ;
2024-03-04 17:47:34 +01:00
if ( isset ( $user_config [ 'hide_unsub' ]) && $user_config [ 'hide_unsub' ] == 'hide' ) {
echo '<font class="np_last_posted_date"> Unsubscribed groups are HIDDEN. Visit <a href="/spoolnews/user.php">User/Configuration</a> to change<br />' ;
echo ' or select groups from <a href="/common/grouplist.php">Grouplist</a> to add groups</font>' ;
}
2020-11-29 01:55:31 +01:00
}
/*
* print the group names from an array to the webpage
*/
2023-08-20 00:33:05 +02:00
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 " ;
2020-11-29 01:55:31 +01:00
}
/*
2023-04-14 03:52:30 +02:00
* gets a list of available articles in the group $groupname
2020-11-29 01:55:31 +01:00
*/
/*
2023-08-20 00:33:05 +02:00
* 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 ;
* }
*/
2020-11-29 01:55:31 +01:00
/*
* Decode quoted - printable or base64 encoded headerlines
*
* $value : The to be decoded line
*
* returns the decoded line
*/
2023-08-20 00:33:05 +02:00
function headerDecode ( $value )
{
2024-02-02 18:20:37 +01:00
$value = preg_replace_callback ( '/(=\?[^\?]+\?Q\?)([^\?]+)(\?=)/i' , function ( $matches ) {
2024-01-11 15:49:04 +01:00
return $matches [ 1 ] . str_replace ( '_' , '=20' , $matches [ 2 ]) . $matches [ 3 ];
}, $value );
2023-08-20 00:33:05 +02:00
return mb_decode_mimeheader ( $value );
2020-11-29 01:55:31 +01:00
}
/*
* calculates an Unix timestamp out of a Date - Header in an article
*
* $value : Value of the Date : header
*
* returns an Unix timestamp
*/
2023-08-20 00:33:05 +02:00
function getTimestamp ( $value )
{
global $CONFIG ;
2020-11-29 01:55:31 +01:00
2023-08-20 00:33:05 +02:00
return strtotime ( $value );
2020-11-29 01:55:31 +01:00
}
2023-08-20 00:33:05 +02:00
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 ;
2023-09-17 14:39:31 +02:00
case " content-disposition: " :
2023-09-19 12:06:57 +02:00
$getname = preg_split ( " /name \ =/ " , $value , 2 );
if ( isset ( $getname [ 1 ])) {
$header -> content_type_name = array (
$getname [ 1 ]
);
}
2023-09-17 14:39:31 +02:00
break ;
2023-08-20 00:33:05 +02:00
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: " :
2023-09-11 02:31:47 +02:00
case " x-rslight-to: " :
$header -> rslight_to = trim ( $value );
2023-08-20 00:33:05 +02:00
break ;
2023-09-11 02:31:47 +02:00
case " x-rslight-site: " :
$header -> rslight_site = trim ( $value );
2023-08-20 00:33:05 +02:00
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 ;
2020-11-29 01:55:31 +01:00
}
/*
* convert the charset of a text
*/
2023-08-20 00:33:05 +02:00
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 ;
}
2020-11-29 01:55:31 +01:00
}
2023-08-20 00:33:05 +02:00
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 ;
2020-11-29 01:55:31 +01:00
}
/*
* 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 .
*/
2023-08-20 00:33:05 +02:00
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 ];
// add the spaces between the words
if ( $i > 0 )
$ntext .= " " ;
$ntext .= $word ;
}
return ( $ntext );
2020-11-29 01:55:31 +01:00
}
2023-09-02 16:38:59 +02:00
function display_links_in_body ( $text )
{
2024-03-20 16:18:22 +01:00
preg_match_all ( '/(https?|ftp|scp|news|gopher|gemini|telnet):\/\/[a-zA-Z0-9.?%=\-\+\;\:\,\~\@\!\(\)\$\#&_\/]+/' , $text , $matches );
2023-09-02 16:38:59 +02:00
$found = array ();
2023-09-19 12:06:57 +02:00
$isquote = false ;
if ( strpos ( $text , " > " ) == 0 ) {
$isquote = true ;
echo '<blockquote class="np_article_quote">' ;
}
2023-09-02 16:38:59 +02:00
foreach ( $matches [ 0 ] as $match ) {
if ( ! $match ) {
continue ;
}
if ( in_array ( $match , $found )) {
continue ;
}
$found [] = $match ;
$linkurl = preg_replace ( " /(<|>)/ " , ' ' , htmlspecialchars_decode ( $match ));
$url = preg_replace ( " /(<|>)/ " , ' ' , $match );
$pattern = preg_quote ( $url );
$pattern = " ! $pattern ! " ;
$text = preg_replace ( $pattern , '<a href="' . $linkurl . '" rel="nofollow" target="_blank">' . $url . '</a>' , $text , 1 );
}
echo $text ;
2023-09-19 12:06:57 +02:00
if ( $isquote ) {
echo '</blockquote>' ;
}
2023-09-02 16:38:59 +02:00
}
2020-11-29 01:55:31 +01:00
/*
* read the header of an article in plaintext into an array
* $articleNumber can be the number of an article or its message - id .
*/
2023-08-20 00:33:05 +02:00
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 ));
}
2020-11-29 01:55:31 +01:00
}
/*
* 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
*/
2023-08-20 00:33:05 +02:00
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 ;
2020-11-29 01:55:31 +01:00
}
2023-08-20 00:33:05 +02:00
2023-09-11 02:31:47 +02:00
function rslight_encrypt ( $data , $key )
2023-08-20 00:33:05 +02:00
{
2020-11-29 01:55:31 +01:00
$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 );
}
2023-08-20 00:33:05 +02:00
function _rawurlencode ( $string )
{
$string = rawurlencode ( str_replace ( '+' , '%2B' , $string ));
2020-11-29 01:55:31 +01:00
return $string ;
}
2023-08-20 00:33:05 +02:00
function _rawurldecode ( $string )
{
$string = rawurldecode ( str_replace ( '%2B' , '+' , $string ));
2020-11-29 01:55:31 +01:00
return $string ;
}
2023-09-11 02:31:47 +02:00
function rslight_decrypt ( $data , $key )
2023-08-20 00:33:05 +02:00
{
2020-11-29 01:55:31 +01:00
$encryption_key = base64_decode ( $key );
2023-08-20 00:33:05 +02:00
list ( $encrypted_data , $iv ) = explode ( '::' , base64_decode ( $data ), 2 );
2020-11-29 01:55:31 +01:00
return openssl_decrypt ( $encrypted_data , 'aes-256-cbc' , $encryption_key , 0 , $iv );
}
function group_display_name ( $gname )
{
global $config_dir ;
2023-08-20 00:33:05 +02:00
$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 ];
}
2020-11-29 01:55:31 +01:00
}
return $gname ;
}
2023-08-20 00:33:05 +02:00
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' ])) {
2023-09-11 02:31:47 +02:00
if ( filemtime ( $config_dir . " rslight.inc.php " ) > filemtime ( $userFilename )) {
2023-08-20 00:33:05 +02:00
if ( $userFileHandle = fopen ( $userFilename , 'w+' )) {
fwrite ( $userFileHandle , password_hash ( $CONFIG [ 'anonuserpass' ], PASSWORD_DEFAULT ));
fclose ( $userFileHandle );
}
}
}
if ( $username == strtolower ( $CONFIG [ 'server_auth_user' ])) {
2023-09-11 02:31:47 +02:00
if ( filemtime ( $config_dir . " rslight.inc.php " ) > filemtime ( $userFilename )) {
2023-08-20 00:33:05 +02:00
if ( $userFileHandle = fopen ( $userFilename , 'w+' )) {
fwrite ( $userFileHandle , password_hash ( $CONFIG [ 'server_auth_pass' ], PASSWORD_DEFAULT ));
fclose ( $userFileHandle );
}
}
2020-11-29 01:55:31 +01:00
}
2023-08-20 00:33:05 +02:00
if ( trim ( $username ) == strtolower ( $CONFIG [ 'anonusername' ]) && $CONFIG [ 'anonuser' ] != true ) {
return FALSE ;
}
2021-02-10 06:18:28 +01:00
2023-08-20 00:33:05 +02:00
if ( $userFileHandle = fopen ( $userFilename , 'r' )) {
2020-11-29 01:55:31 +01:00
$userFileInfo = fread ( $userFileHandle , filesize ( $userFilename ));
fclose ( $userFileHandle );
2023-08-20 00:33:05 +02:00
if ( password_verify ( $password , $userFileInfo )) {
touch ( $userFilename );
$ok = TRUE ;
2020-11-29 01:55:31 +01:00
} else {
2023-08-20 00:33:05 +02:00
return FALSE ;
2020-11-29 01:55:31 +01:00
}
2023-08-20 00:33:05 +02:00
} else {
2020-11-29 01:55:31 +01:00
$ok = FALSE ;
2023-08-20 00:33:05 +02:00
}
if ( $ok ) {
2020-11-29 01:55:31 +01:00
return TRUE ;
2023-08-20 00:33:05 +02:00
} 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 ;
}
}
2020-11-29 01:55:31 +01:00
}
2023-08-20 00:33:05 +02:00
function check_encryption_groups ( $request )
{
2024-02-09 18:39:09 +01:00
global $config_dir ;
$groupsFilename = $config_dir . " encryption_ok.txt " ;
2023-08-20 00:33:05 +02:00
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 );
2020-12-03 03:00:17 +01:00
} else {
2023-08-20 00:33:05 +02:00
return FALSE ;
}
2020-12-03 03:00:17 +01:00
}
2023-08-20 00:33:05 +02:00
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 " );
2020-11-29 01:55:31 +01:00
}
fclose ( $userFileHandle );
2023-08-20 00:33:05 +02:00
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 ;
}
2020-11-29 01:55:31 +01:00
}
2023-08-20 00:33:05 +02:00
function is_multibyte ( $s )
{
return mb_strlen ( $s , 'utf-8' ) < strlen ( $s );
2020-11-29 01:55:31 +01:00
}
2023-12-26 17:05:40 +01:00
function check_spam ( $subject , $from , $newsgroups , $ref , $body , $msgid , $useheaders = false )
2020-11-29 01:55:31 +01:00
{
2023-10-07 03:32:05 +02:00
global $msgid_generate , $msgid_fqdn , $spooldir , $logdir ;
2023-08-20 00:33:05 +02:00
global $CONFIG ;
2023-12-26 17:05:40 +01:00
$spamdir = $spooldir . '/spam' ;
if ( ! is_dir ( $spamdir )) {
mkdir ( $spamdir );
}
2023-10-07 03:32:05 +02:00
$logfile = $logdir . '/spam.log' ;
2023-08-20 00:33:05 +02:00
$spamfile = tempnam ( $spooldir , 'spam-' );
2023-12-26 17:05:40 +01:00
if ( $useheaders ) {
// Add headers
$head = '' ;
if ( trim ( $subject ) != '' ) {
$head .= 'Subject: ' . $subject . " \r \n " ;
}
if ( trim ( $from ) != '' ) {
$head .= 'From: ' . $from . " \r \n " ;
}
if ( trim ( $newsgroups ) != '' ) {
$head .= 'Newsgroups: ' . $newsgroups . " \r \n " ;
}
if ( trim ( $ref ) != '' ) {
$head .= 'References: ' . $ref . " \r \n " ;
}
if ( trim ( $msgid ) != '' ) {
$head .= 'Message-ID: ' . $msgid . " \r \n " ;
}
$message = $head . " \r \n " . $body ;
} else {
$message = $body ;
}
file_put_contents ( $spamfile , $message );
2023-12-23 14:44:03 +01:00
$spamcommand = $CONFIG [ 'spamc' ] . ' -E < ' . $spamfile ;
ob_start ();
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 ;
}
if (( strpos ( $line , " X-Spam-Flag: YES " ) === 0 ) && ( $res !== 1 )) {
$res = 1 ;
2023-08-20 00:33:05 +02:00
}
2020-11-29 01:55:31 +01:00
}
unlink ( $spamfile );
2023-10-07 03:32:05 +02:00
if ( $res === 1 ) {
2024-01-02 13:16:53 +01:00
file_put_contents ( $logfile , " \n " . format_log_date () . " spamc: \t SPAM \t " . $msgid . " \t " . $newsgroups . " \t " . preg_replace ( '/\t/' , ' ' , $from ), FILE_APPEND );
2023-12-26 17:05:40 +01:00
file_put_contents ( $spamdir . '/' . $msgid , $spamresult );
2023-12-24 21:11:52 +01:00
} else {
2024-01-02 13:16:53 +01:00
file_put_contents ( $logfile , " \n " . format_log_date () . " spamc: \t HAM \t " . $msgid . " \t " . $newsgroups . " \t " . preg_replace ( '/\t/' , ' ' , $from ), FILE_APPEND );
2023-10-07 03:32:05 +02:00
}
2023-08-20 00:33:05 +02:00
return array (
'res' => $res ,
'spamresult' => $spamresult ,
'spamcheckerversion' => $spamcheckerversion ,
'spamlevel' => $spamlevel ,
'spam_fail' => $spam_fail
);
2020-11-29 01:55:31 +01:00
}
2023-08-20 00:33:05 +02:00
function format_log_date ()
{
2020-11-29 01:55:31 +01:00
return date ( 'M d H:i:s' );
}
2023-08-20 00:33:05 +02:00
function create_name_link ( $name , $data = null )
{
global $CONFIG ;
2021-04-06 10:39:40 +02:00
$name = preg_replace ( '/\"/' , '' , $name );
2023-08-20 00:33:05 +02:00
if ( $data ) {
$data = urlencode ( base64_encode ( $data ));
2022-02-21 05:15:38 +01:00
}
2023-08-20 00:33:05 +02:00
if (( strpos ( $name , '...@' ) !== false && ( isset ( $CONFIG [ 'hide_email' ]) && $CONFIG [ 'hide_email' ] == true )) && ! $data ) {
$return = '<span class="visited">' . substr ( htmlspecialchars ( $name ), 0 , 20 ) . '</span>' ;
2020-11-29 01:55:31 +01:00
} else {
2024-02-29 19:37:59 +01:00
$return = '<a href="search.php?command=search&searchpoint=Poster&terms=' . $name . '&data=' . $data . '" title="Search by user"><span class="visited">' . substr ( htmlspecialchars ( $name ), 0 , 20 ) . '</span></a>' ;
2020-11-29 01:55:31 +01:00
}
2023-08-20 00:33:05 +02:00
return ( $return );
2020-11-29 01:55:31 +01:00
}
2023-08-20 00:33:05 +02:00
function truncate_email ( $address )
{
2020-11-29 01:55:31 +01:00
$before_at = explode ( '@' , $address );
2023-08-20 00:33:05 +02:00
$namelen = strlen ( $before_at [ 0 ]);
if ( $namelen > 3 ) {
2020-11-29 01:55:31 +01:00
$endname = $namelen - 3 ;
2023-08-20 00:33:05 +02:00
if ( $endname > 8 )
$endname = 8 ;
if ( $endname < 3 )
$endname ++ ;
if ( $endname < 3 )
$endname ++ ;
} else {
2020-11-29 01:55:31 +01:00
$endname = $namelen ;
2023-08-20 00:33:05 +02:00
}
return substr ( $before_at [ 0 ], 0 , $endname ) . '...' . substr ( $address , $namelen , strlen ( $address ));
2020-11-29 01:55:31 +01:00
}
2023-08-20 00:33:05 +02:00
function get_date_interval ( $value )
{
2020-11-29 01:55:31 +01:00
$current = time ();
$datetime1 = date_create ( $value );
$datetime2 = date_create ( " @ $current " );
$interval = date_diff ( $datetime1 , $datetime2 );
2023-08-20 00:33:05 +02:00
if ( ! $interval ) {
return '(date error)' ;
2021-02-21 07:36:50 +01:00
}
2023-08-20 00:33:05 +02:00
$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 " ;
2020-11-29 01:55:31 +01:00
}
2023-08-20 00:33:05 +02:00
if ( $interval -> format ( '%m' ) == 1 ) {
$months = $interval -> format ( '%m' ) . " Month " ;
2020-11-29 01:55:31 +01:00
}
2023-08-20 00:33:05 +02:00
if ( $interval -> format ( '%d' ) == 1 ) {
$days = $interval -> format ( '%d' ) . " Day " ;
2020-11-29 01:55:31 +01:00
}
2023-08-20 00:33:05 +02:00
if ( $interval -> format ( '%h' ) == 1 ) {
$hours = $interval -> format ( '%h' ) . " Hour " ;
2020-11-29 01:55:31 +01:00
}
2023-08-20 00:33:05 +02:00
if ( $interval -> format ( '%i' ) == 1 ) {
$minutes = $interval -> format ( '%i' ) . " Minute " ;
2020-11-29 01:55:31 +01:00
}
2023-08-20 00:33:05 +02:00
if ( $interval -> format ( '%y' ) == 0 ) {
2020-11-29 01:55:31 +01:00
$years = '' ;
}
2023-08-20 00:33:05 +02:00
if ( $interval -> format ( '%m' ) == 0 ) {
2020-11-29 01:55:31 +01:00
$months = '' ;
}
2023-08-20 00:33:05 +02:00
if ( $interval -> format ( '%d' ) == 0 ) {
2020-11-29 01:55:31 +01:00
$days = '' ;
}
2023-08-20 00:33:05 +02:00
if ( $interval -> format ( '%h' ) == 0 ) {
2020-11-29 01:55:31 +01:00
$hours = '' ;
}
2023-08-20 00:33:05 +02:00
if ( $interval -> format ( '%i' ) == 0 ) {
2020-11-29 01:55:31 +01:00
$minutes = '' ;
}
2023-08-20 00:33:05 +02:00
if ( $years > 0 ) {
$days = '' ;
2020-11-29 01:55:31 +01:00
$hours = '' ;
2023-08-20 00:33:05 +02:00
$minutes = '' ;
2020-11-29 01:55:31 +01:00
}
2023-08-20 00:33:05 +02:00
if ( $months > 0 ) {
$hours = '' ;
2020-11-29 01:55:31 +01:00
$minutes = '' ;
}
2023-08-20 00:33:05 +02:00
if ( $days > 0 ) {
$minutes = '' ;
2020-11-29 01:55:31 +01:00
}
2023-08-20 00:33:05 +02:00
$variance = $interval -> format ( $years . $months . $days . $hours . $minutes . ' ago' );
if ( strlen ( $variance ) < 5 ) {
$variance = " now " ;
2020-11-29 01:55:31 +01:00
}
return $variance ;
}
2020-12-12 05:16:13 +01:00
2023-11-15 12:55:08 +01:00
function create_xref_from_msgid ( $msgid , $thisgroup = null , $thisnumber = null )
{
global $spooldir , $CONFIG ;
$database = $spooldir . '/articles-overview.db3' ;
$table = 'overview' ;
$overview_dbh = overview_db_open ( $database , $table );
$overview_stmt = $overview_dbh -> prepare ( " SELECT * FROM overview WHERE msgid=:msgid " );
$overview_stmt -> bindParam ( ':msgid' , $msgid );
$overview_stmt -> execute ();
$found = false ;
$xref = " Xref: " . $CONFIG [ 'pathhost' ];
while ( $row = $overview_stmt -> fetch ()) {
if ( $row [ 'newsgroup' ] == $thisgroup && $thisgroup != null ) {
$found = true ;
}
$xref .= ' ' . $row [ 'newsgroup' ] . ':' . $row [ 'number' ];
}
2023-12-23 14:44:03 +01:00
if ( ! $found ) {
2023-11-15 12:55:08 +01:00
$xref .= ' ' . $thisgroup . ':' . $thisnumber ;
}
$overview_dbh = null ;
return ( $xref );
}
2023-08-20 00:33:05 +02:00
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 " )) {
2021-03-08 09:43:06 +01:00
$mysnippet = substr ( $mysnippet , 0 , $bodyend );
2023-08-20 00:33:05 +02:00
} else {
if ( $bodyend = strrpos ( $mysnippet , " \n -- " )) {
2021-03-08 09:43:06 +01:00
$mysnippet = substr ( $mysnippet , 0 , $bodyend );
} else {
2023-08-20 00:33:05 +02:00
if ( $bodyend = strrpos ( $mysnippet , " \n . " )) {
$mysnippet = substr ( $mysnippet , 0 , $bodyend );
2021-03-08 09:43:06 +01:00
}
}
2023-08-20 00:33:05 +02:00
}
$mysnippet = preg_replace ( '/\n.{0,5}>(.*)/' , '' , $mysnippet );
2021-03-08 09:43:06 +01:00
2023-08-20 00:33:05 +02:00
$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 ;
2021-03-08 09:43:06 +01:00
}
2023-08-20 00:33:05 +02:00
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(
2021-06-21 11:04:13 +02:00
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 ) " );
2023-08-20 00:33:05 +02:00
return ( $dbh );
2021-06-21 11:04:13 +02:00
}
2023-08-23 21:25:21 +02:00
function threads_db_open ( $database , $table = " threads " )
2023-08-22 14:34:37 +02:00
{
try {
$dbh = new PDO ( 'sqlite:' . $database );
} catch ( PDOException $e ) {
echo 'Connection failed: ' . $e -> getMessage ();
exit ();
}
2024-03-17 19:22:00 +01:00
$dbh -> exec ( " CREATE TABLE IF NOT EXISTS threads(
2023-08-22 14:34:37 +02:00
id INTEGER PRIMARY KEY ,
headers TEXT ,
unique ( headers )) " );
return ( $dbh );
}
2023-08-20 00:33:05 +02:00
function history_db_open ( $database , $table = 'history' )
{
try {
$dbh = new PDO ( 'sqlite:' . $database );
} catch ( PDOException $e ) {
echo 'Connection failed: ' . $e -> getMessage ();
exit ();
}
2024-03-17 19:22:00 +01:00
$dbh -> exec ( " CREATE TABLE IF NOT EXISTS history(
id INTEGER PRIMARY KEY ,
newsgroup TEXT ,
2023-08-16 18:41:13 +02:00
number TEXT ,
msgid TEXT ,
status TEXT ,
statusdate TEXT ,
statusreason TEXT ,
statusnotes TEXT ,
unique ( newsgroup , msgid ),
2023-08-20 00:33:05 +02:00
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 );
2023-08-16 18:41:13 +02:00
}
2023-08-20 00:33:05 +02:00
function overview_db_open ( $database , $table = 'overview' )
{
try {
$dbh = new PDO ( 'sqlite:' . $database );
} catch ( PDOException $e ) {
echo 'Connection failed: ' . $e -> getMessage ();
exit ();
}
2024-03-17 19:22:00 +01:00
$dbh -> exec ( " CREATE TABLE IF NOT EXISTS overview(
2020-12-12 05:16:13 +01:00
id INTEGER PRIMARY KEY ,
newsgroup TEXT ,
number TEXT ,
2021-02-19 06:10:43 +01:00
msgid TEXT ,
2020-12-12 05:16:13 +01:00
date TEXT ,
2023-08-13 14:08:04 +02:00
datestring TEXT ,
2020-12-12 05:16:13 +01:00
name TEXT ,
2021-02-21 07:36:50 +01:00
subject TEXT ,
2023-08-13 14:08:04 +02:00
refs TEXT ,
bytes TEXT ,
lines TEXT ,
xref TEXT ,
2023-08-23 21:25:21 +02:00
unique ( newsgroup , msgid ),
unique ( newsgroup , number )) " );
2023-08-20 00:33:05 +02:00
$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 );
2020-12-12 05:16:13 +01:00
}
2021-01-20 23:54:47 +01:00
2023-08-20 00:33:05 +02:00
function article_db_open ( $database , $table = 'articles' )
{
try {
$dbh = new PDO ( 'sqlite:' . $database );
} catch ( PDOException $e ) {
echo 'Connection failed: ' . $e -> getMessage ();
exit ();
}
2024-03-17 19:22:00 +01:00
$dbh -> exec ( " CREATE TABLE IF NOT EXISTS articles(
2021-01-20 23:54:47 +01:00
id INTEGER PRIMARY KEY ,
newsgroup TEXT ,
2021-02-19 06:10:43 +01:00
number TEXT UNIQUE ,
2021-02-17 07:49:46 +01:00
msgid TEXT UNIQUE ,
2021-01-20 23:54:47 +01:00
date TEXT ,
name TEXT ,
subject TEXT ,
2021-03-08 09:43:06 +01:00
search_snippet TEXT ,
2021-01-20 23:54:47 +01:00
article TEXT ) " );
2021-04-03 11:10:20 +02:00
2023-08-20 00:33:05 +02:00
$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 ();
2021-04-02 03:36:14 +02:00
2023-08-20 00:33:05 +02:00
$dbh -> exec ( " CREATE VIRTUAL TABLE IF NOT EXISTS search_fts USING fts5(
2021-03-08 09:43:06 +01:00
newsgroup ,
number ,
msgid ,
2021-03-11 07:55:01 +01:00
date ,
name ,
2021-03-08 09:43:06 +01:00
subject ,
search_snippet ) " );
2023-08-20 00:33:05 +02:00
$dbh -> exec ( " CREATE TRIGGER IF NOT EXISTS after_articles_insert AFTER INSERT ON $table BEGIN
2021-03-11 07:55:01 +01:00
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 );
2021-03-08 09:43:06 +01:00
END ; " );
2023-08-20 00:33:05 +02:00
$dbh -> exec ( " CREATE TRIGGER IF NOT EXISTS after_articles_delete AFTER DELETE ON $table BEGIN
2021-03-08 09:43:06 +01:00
DELETE FROM search_fts WHERE msgid = old . msgid ;
2023-08-20 00:33:05 +02:00
END ; " );
return ( $dbh );
2021-01-20 23:54:47 +01:00
}
2023-08-20 00:33:05 +02:00
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 ;
2021-01-20 23:54:47 +01:00
}
2021-01-28 07:10:32 +01:00
$ok_article = 0 ;
2023-08-20 00:33:05 +02:00
// 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 ;
}
2021-01-20 23:54:47 +01:00
} else {
2023-08-20 00:33:05 +02:00
$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 ;
}
2021-01-20 23:54:47 +01:00
}
2023-08-20 00:33:05 +02:00
if ( $closeme == 1 ) {
$dbh = null ;
2021-01-20 23:54:47 +01:00
}
2023-08-20 00:33:05 +02:00
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 ;
2021-01-28 07:10:32 +01:00
}
2023-08-20 00:33:05 +02:00
// 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 ;
2021-01-20 23:54:47 +01:00
} else {
2023-08-20 00:33:05 +02:00
return trim ( $msg2 );
2021-01-20 23:54:47 +01:00
}
}
2023-08-20 00:33:05 +02:00
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 );
2022-04-10 06:30:34 +02:00
}
2024-03-02 18:54:28 +01:00
/*
* This function returns false on success
* or return value contains error info
* 'added' etc .
2024-03-04 17:47:34 +01:00
*/
2024-03-02 18:54:28 +01:00
function save_config_value ( $configfile , $name , $value , $value_unique = false )
2024-02-02 18:20:37 +01:00
{
2024-03-02 18:54:28 +01:00
global $spooldir ;
$return_val = false ;
$tempfile = tempnam ( $spooldir , 'rslight-' );
2024-03-04 17:47:34 +01:00
if ( file_exists ( $tempfile )) {
2024-03-02 18:54:28 +01:00
unlink ( $tempfile );
}
$lines = file ( $configfile , FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES );
$found = false ;
foreach ( $lines as $line ) {
$current = explode ( ':' , $line );
if ( $value_unique && ( strcmp ( $current [ 1 ], $value ) == 0 )) {
// Found value. Write once
2024-03-04 17:47:34 +01:00
if ( ! $found ) {
2024-03-02 18:54:28 +01:00
file_put_contents ( $tempfile , $name . " : " . $value . " \n " , FILE_APPEND );
}
$found = true ;
continue ;
}
if ( strcmp ( $current [ 0 ], $name ) == 0 ) {
// $name matches option. Overwrite
file_put_contents ( $tempfile , $name . " : " . $value . " \n " , FILE_APPEND );
$found = true ;
2023-12-27 11:18:48 +01:00
} else {
2024-03-02 18:54:28 +01:00
// $name does not match option. Keep current line
file_put_contents ( $tempfile , $line . " \n " , FILE_APPEND );
2023-12-27 11:18:48 +01:00
}
}
2024-03-04 17:47:34 +01:00
if ( ! $found ) {
2024-03-02 18:54:28 +01:00
// $name not found in options. Add to file.
file_put_contents ( $tempfile , $name . " : " . $value . " \n " , FILE_APPEND );
}
copy ( $tempfile , $configfile );
unlink ( $tempfile );
return $return_val ;
2023-12-27 11:18:48 +01:00
}
function get_config_file_value ( $configfile , $request )
{
if ( $configFileHandle = @ fopen ( $configfile , 'r' )) {
while ( ! feof ( $configFileHandle )) {
$buffer = fgets ( $configFileHandle );
if ( strpos ( $buffer , $request . ':' ) !== FALSE ) {
$dataline = $buffer ;
fclose ( $configFileHandle );
$datafound = explode ( ':' , $dataline );
return trim ( $datafound [ 1 ]);
}
}
fclose ( $configFileHandle );
return FALSE ;
} else {
return FALSE ;
}
}
2024-02-02 18:20:37 +01:00
// This function is specific to $config_dir configuration values
2023-08-20 00:33:05 +02:00
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 );
2023-09-16 18:36:02 +02:00
return trim ( $datafound [ 1 ]);
2023-08-20 00:33:05 +02:00
}
}
2020-12-19 02:14:39 +01:00
fclose ( $configFileHandle );
2023-08-20 00:33:05 +02:00
return FALSE ;
} else {
return FALSE ;
}
2020-12-19 02:14:39 +01:00
}
2021-06-18 12:10:34 +02:00
2023-09-04 15:06:43 +02:00
function disable_page_by_user_agent ( $client_device , $useragent , $script = " Page " )
{
2023-09-06 13:07:57 +02:00
global $logdir , $config_name ;
2023-09-04 15:06:43 +02:00
if ( $client_device == $useragent ) {
$logfile = $logdir . '/device.log' ;
file_put_contents ( $logfile , " \n " . date ( 'M d H:i:s' ) . " " . $config_name . " " . $script . " disabled for ' " . $useragent . " ' Exiting... " , FILE_APPEND );
if ( $client_device == " bot " ) {
2023-09-06 13:07:57 +02:00
$_SESSION [ 'bot' ] = true ;
2023-09-04 15:06:43 +02:00
}
return true ;
} else {
return false ;
}
}
2023-09-06 13:07:57 +02:00
function throttle_hits ( $client_device )
2023-08-20 00:33:05 +02:00
{
2023-09-06 13:07:57 +02:00
global $CONFIG , $logdir ;
$client_device = get_client_user_agent_info ();
$_SESSION [ 'rsactive' ] = true ;
2023-09-04 16:07:06 +02:00
if ( $client_device == " bot " ) {
$_SESSION [ 'bot' ] = 'true' ;
}
2023-08-20 00:33:05 +02:00
$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 ;
}
exit ( 0 );
}
2023-09-06 13:33:59 +02:00
if ( isset ( $_SESSION [ 'throttled' ])) {
unset ( $_SESSION [ 'throttled' ]);
}
2023-09-06 13:07:57 +02:00
}
function get_client_user_agent_info ()
{
2023-09-08 14:09:37 +02:00
global $config_dir ;
2023-09-06 13:07:57 +02:00
// Try to get browser info to use for extra formatting of page
$ua = strtolower ( $_SERVER [ " HTTP_USER_AGENT " ]);
$devices = array (
" bot " ,
" spider " ,
" mobile " ,
" lynx " ,
" w3m " ,
" links " ,
" ipad " ,
" tablet "
);
$client_device = " desktop " ;
foreach ( $devices as $device ) {
if ( strpos ( $ua , $device ) !== false ) {
$client_device = $device ;
break ;
}
}
if ( $client_device == " spider " ) {
$client_device = " bot " ;
}
// Log client device if enabled by semaphore
if ( file_exists ( $config_dir . '/devicelog.enable' )) {
$client_ip = getenv ( " REMOTE_ADDR " );
$logfile = $logdir . '/device.log' ;
file_put_contents ( $logfile , " \n " . date ( 'M d H:i:s' ) . " " . $config_name . " Client: " . $client_ip . " browser: " . $client_device , FILE_APPEND );
file_put_contents ( $logfile , " \n Full UA: " . $ua , FILE_APPEND );
}
return $client_device ;
2021-06-18 12:10:34 +02:00
}
2021-12-31 10:41:53 +01:00
2023-08-20 00:33:05 +02:00
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 ));
2024-03-17 19:22:00 +01:00
if ( isset ( $userdata [ 'DO.NOT.DELETE' ])) {
2024-03-03 21:55:26 +01:00
$userdata [ 'DO.NOT.DELETE' ] = time ();
}
} else {
$userdata [ 'DO.NOT.DELETE' ] = time ();
2023-08-20 00:33:05 +02:00
}
return $userdata ;
}
2022-03-16 07:54:34 +01:00
return false ;
2022-01-20 05:05:06 +01:00
}
2023-08-20 00:33:05 +02:00
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 );
2022-02-09 06:51:20 +01:00
}
2023-08-20 00:33:05 +02:00
function verify_gpg_signature ( $res , $signed_text )
{
$result = gnupg_verify ( $res , $signed_text , false );
2023-07-30 17:59:09 +02:00
if ( $result == false ) {
return false ;
}
2023-08-20 00:33:05 +02:00
if ((( $result [ 0 ][ 'summary' ] > 3 )) || $result [ 0 ][ 'validity' ] == 2 ) {
return false ; // Bad signature
2023-07-26 21:36:42 +02:00
} else {
2023-08-20 00:33:05 +02:00
return true ; // Good signature
2023-07-26 21:36:42 +02:00
}
}
2023-10-24 04:01:30 +02:00
function get_next_article_number ( $group )
{
$ok_article = get_article_list ( $group );
sort ( $ok_article );
$local = $ok_article [ key ( array_slice ( $ok_article , - 1 , 1 , true ))];
if ( ! is_numeric ( $local )) {
$local = 0 ;
}
$local = $local + 1 ;
if ( $local < 1 ) {
$local = 1 ;
}
while ( is_deleted_post ( $group , $local )) {
$local ++ ;
}
return $local ;
}
2023-12-26 17:05:40 +01:00
function check_duplicate_msgid ( $msgid , $group )
{
global $spooldir , $logdir ;
$found = false ;
$database = $spooldir . '/articles-overview.db3' ;
$table = 'overview' ;
$dbh = overview_db_open ( $database , $table );
$stmt = $dbh -> prepare ( " SELECT * FROM $table WHERE msgid=:msgid AND newsgroup=:newsgroup " );
$stmt -> bindParam ( ':msgid' , $msgid );
$stmt -> bindParam ( ':newsgroup' , $group );
$stmt -> execute ();
while ( $row = $stmt -> fetch ()) {
2024-02-02 18:20:37 +01:00
if ( $row [ 'msgid' ] == $msgid ) {
2023-12-26 17:05:40 +01:00
$found = true ;
}
}
$dbh = null ;
$database = $spooldir . '/history.db3' ;
$table = 'history' ;
$dbh = history_db_open ( $database , $table );
$stmt = $dbh -> prepare ( " SELECT * FROM $table WHERE msgid=:msgid AND newsgroup=:newsgroup " );
$stmt -> bindParam ( ':msgid' , $msgid );
$stmt -> bindParam ( ':newsgroup' , $group );
$stmt -> execute ();
while ( $row = $stmt -> fetch ()) {
2024-02-02 18:20:37 +01:00
if ( $row [ 'msgid' ] == $msgid ) {
2023-12-26 17:05:40 +01:00
$found = true ;
}
}
$dbh = null ;
return $found ;
}
2023-12-24 14:49:34 +01:00
function insert_article_from_array ( $this_article , $check_duplicates = true )
2023-10-24 04:01:30 +02:00
{
global $CONFIG , $config_name , $spooldir , $logdir ;
$logfile = $logdir . '/spoolnews.log' ;
$group = $this_article [ 'group' ];
$grouppath = $path . preg_replace ( '/\./' , '/' , $group );
2023-12-24 14:49:34 +01:00
if ( $check_duplicates ) {
2023-12-26 17:05:40 +01:00
if ( check_duplicate_msgid ( $this_article [ 'mid' ], $group )) {
echo " \n (newsportal)Duplicate Message-ID for: " . $group . " : " . $this_article [ 'mid' ];
file_put_contents ( $logfile , " \n " . format_log_date () . " " . $config_name . " Duplicate Message-ID for: " . $group . " : " . $this_article [ 'mid' ], FILE_APPEND );
2023-12-24 14:49:34 +01:00
return " 441 Insert failed (duplicate) \r \n " ;
}
2023-10-24 04:01:30 +02:00
}
2023-12-26 17:05:40 +01:00
2023-10-24 04:01:30 +02:00
// Open articles Database
if ( $CONFIG [ 'article_database' ] == '1' ) {
$article_dbh = article_db_open ( $spooldir . '/' . $group . '-articles.db3' );
2023-12-27 13:07:31 +01:00
$article_sql = 'INSERT OR IGNORE INTO articles(newsgroup, number, msgid, date, name, subject, article, search_snippet) VALUES(?,?,?,?,?,?,?,?)' ;
2023-10-24 04:01:30 +02:00
$article_stmt = $article_dbh -> prepare ( $article_sql );
}
// Open overview database
$database = $spooldir . '/articles-overview.db3' ;
$table = 'overview' ;
$overview_dbh = overview_db_open ( $database , $table );
2023-12-27 13:07:31 +01:00
$overview_sql = 'INSERT OR IGNORE INTO overview(newsgroup, number, msgid, date, datestring, name, subject, refs, bytes, lines, xref) VALUES(?,?,?,?,?,?,?,?,?,?,?)' ;
2023-10-24 04:01:30 +02:00
$overview_stmt = $overview_dbh -> prepare ( $overview_sql );
// Overview
$overview_stmt -> execute ([
$group ,
$this_article [ 'local' ],
$this_article [ 'mid' ],
$this_article [ 'epochdate' ],
$this_article [ 'stringdate' ],
$this_article [ 'from' ],
$this_article [ 'subject' ],
$this_article [ 'references' ],
$this_article [ 'bytes' ],
$this_article [ 'lines' ],
$this_article [ 'xref' ]
]);
$overview_dbh = null ;
$references = " " ;
// Articles
if ( $CONFIG [ 'article_database' ] == '1' ) {
$article_stmt -> execute ([
$group ,
$this_article [ 'local' ],
$this_article [ 'mid' ],
$this_article [ 'epochdate' ],
$this_article [ 'from' ],
$this_article [ 'subject' ],
$this_article [ 'article' ],
$this_article [ 'snippet' ]
]);
unlink ( $grouppath . " / " . $this_article [ 'local' ]);
$article_dbh = null ;
} else {
if ( $article_date > time ())
$article_date = time ();
2023-11-15 12:55:08 +01:00
touch ( $grouppath . " / " . $this_article [ 'local' ], $article_date );
2023-10-24 04:01:30 +02:00
}
2023-12-26 17:05:40 +01:00
echo " \n Spooling: " . $group . " " . $this_article [ 'local' ];
2023-10-24 04:01:30 +02:00
file_put_contents ( $logfile , " \n " . format_log_date () . " " . $config_name . " Spooling: " . $group . " : " . $this_article [ 'local' ], FILE_APPEND );
$status = " spooled " ;
$statusdate = time ();
$statusreason = " imported " ;
add_to_history ( $group , $this_article [ 'local' ], $this_article [ 'mid' ], $status , $statusdate , $statusreason , $statusnotes );
}
2023-08-20 00:33:05 +02:00
function is_deleted_post ( $group , $number )
{
2023-08-16 18:41:13 +02:00
global $spooldir ;
2023-08-20 00:33:05 +02:00
$database = $spooldir . '/history.db3' ;
2023-08-16 18:41:13 +02:00
$table = 'history' ;
$dbh = history_db_open ( $database , $table );
2023-10-24 04:01:30 +02:00
$stmt = $dbh -> prepare ( " SELECT * FROM $table WHERE newsgroup=:newsgroup AND number=:newsnum " );
2023-08-16 18:41:13 +02:00
$stmt -> bindParam ( ':newsgroup' , $group );
2023-10-24 04:01:30 +02:00
$stmt -> bindParam ( ':newsnum' , $number );
2023-08-16 18:41:13 +02:00
$stmt -> execute ();
$status = false ;
2023-08-20 00:33:05 +02:00
while ( $row = $stmt -> fetch ()) {
if ( $row [ 'status' ] == " deleted " ) {
2023-08-16 18:41:13 +02:00
$status = " 430 Article Deleted " ;
break ;
}
}
$dbh = null ;
return $status ;
}
2023-08-20 00:33:05 +02:00
function add_to_history ( $group , $number , $msgid , $status , $statusdate , $statusreason = null , $statusnotes = null )
{
2023-08-16 18:41:13 +02:00
global $spooldir ;
2023-08-20 00:33:05 +02:00
$history = $spooldir . '/history.db3' ;
2023-08-16 18:41:13 +02:00
$history_dbh = history_db_open ( $history );
2023-08-26 12:43:11 +02:00
$history_sql = 'INSERT OR REPLACE INTO history(newsgroup, number, msgid, status, statusdate, statusreason, statusnotes) VALUES(?,?,?,?,?,?,?)' ;
2023-08-16 18:41:13 +02:00
$history_stmt = $history_dbh -> prepare ( $history_sql );
2023-08-20 00:33:05 +02:00
$history_stmt -> execute ([
$group ,
$number ,
$msgid ,
$status ,
$statusdate ,
$statusreason ,
$statusnotes
]);
2023-08-16 18:41:13 +02:00
$history_dbh = null ;
}
2023-09-01 11:46:37 +02:00
function clear_history_by_group ( $group )
{
2023-08-27 16:05:53 +02:00
global $spooldir ;
$history = $spooldir . '/history.db3' ;
$history_dbh = history_db_open ( $history );
$clear_stmt = $history_dbh -> prepare ( " DELETE FROM history WHERE newsgroup=:group " );
$clear_stmt -> bindParam ( ':group' , $group );
$clear_stmt -> execute ();
$history_dbh = null ;
}
2023-08-20 00:33:05 +02:00
function get_db_data_from_msgid ( $msgid , $group )
{
global $spooldir ;
$database = $spooldir . '/' . $group . '-articles.db3' ;
if ( ! is_file ( $database )) {
2022-04-10 06:30:34 +02:00
return false ;
2023-08-20 00:33:05 +02:00
}
$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 ()) {
2022-04-10 06:30:34 +02:00
$found = 1 ;
break ;
2023-08-20 00:33:05 +02:00
}
$dbh = null ;
if ( $found ) {
2022-04-10 06:30:34 +02:00
return $row ;
2023-08-20 00:33:05 +02:00
} else {
2022-04-10 06:30:34 +02:00
return false ;
2023-08-20 00:33:05 +02:00
}
2022-04-10 06:30:34 +02:00
}
2024-02-02 18:20:37 +01:00
function get_data_from_msgid ( $msgid , $thisgroup = null )
2023-08-20 00:33:05 +02:00
{
global $spooldir ;
$database = $spooldir . '/articles-overview.db3' ;
$articles_dbh = overview_db_open ( $database );
2024-02-02 18:20:37 +01:00
if ( $thisgroup != null ) {
$articles_query = $articles_dbh -> prepare ( 'SELECT * FROM overview WHERE msgid=:messageid AND newsgroup=:newsgroup' );
$articles_query -> execute ([
'messageid' => $msgid ,
'newsgroup' => $thisgroup
]);
} else {
$articles_query = $articles_dbh -> prepare ( 'SELECT * FROM overview WHERE msgid=:messageid' );
$articles_query -> execute ([
'messageid' => $msgid
]);
}
2023-08-20 00:33:05 +02:00
$found = 0 ;
while ( $row = $articles_query -> fetch ()) {
2021-12-31 10:41:53 +01:00
$found = 1 ;
break ;
2023-08-20 00:33:05 +02:00
}
$dbh = null ;
if ( $found ) {
2021-12-31 10:41:53 +01:00
return $row ;
2023-08-20 00:33:05 +02:00
} else {
2021-12-31 10:41:53 +01:00
return false ;
2023-08-20 00:33:05 +02:00
}
2021-12-31 10:41:53 +01:00
}
2023-08-08 14:15:24 +02:00
2023-08-20 00:33:05 +02:00
function prune_dir_by_days ( $path , $days )
{
if ( $filenames = array_diff ( scandir ( $path ), array (
'..' ,
'.'
))) {
foreach ( $filenames as $file ) {
2023-08-08 14:15:24 +02:00
$filelastmodified = filemtime ( $path . $file );
2023-08-20 00:33:05 +02:00
if (( time () - $filelastmodified ) > $days * 86400 ) {
if ( is_file ( $path . $file )) {
2023-08-08 14:15:24 +02:00
unlink ( $path . $file );
}
}
}
} else {
return false ;
}
return true ;
}
2023-08-09 19:10:35 +02:00
2024-02-20 15:58:13 +01:00
function check_registered_email_addresses ( $email )
{
global $config_dir ;
$users = scandir ( $config_dir . " /userconfig " );
foreach ( $users as $user ) {
if ( strcmp ( get_user_config ( $user , 'email' ), $email ) == 0 ) {
return $user ;
}
}
return false ;
}
2023-08-20 00:33:05 +02:00
function send_admin_message ( $admin , $from , $subject , $message )
{
2023-08-09 19:10:35 +02:00
global $config_dir , $spooldir ;
2023-08-20 00:33:05 +02:00
if (( $to = get_config_value ( 'aliases.conf' , strtolower ( $admin ))) == false ) {
2023-08-09 19:10:35 +02:00
$to = strtolower ( $admin );
}
$to = trim ( $to );
$from = $to ;
2023-08-20 00:33:05 +02:00
$database = $spooldir . '/mail.db3' ;
2023-08-09 19:10:35 +02:00
$dbh = mail_db_open ( $database );
2023-08-20 00:33:05 +02:00
if ( ! $dbh ) {
2023-08-09 19:10:35 +02:00
echo " Database error \n " ;
return false ;
}
$date = time ();
2023-08-20 00:33:05 +02:00
$msgid = '<' . md5 ( strtolower ( $to ) . strtolower ( $from ) . strtolower ( $subject ) . strtolower ( $message )) . '>' ;
2023-08-09 19:10:35 +02:00
$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 ;
2023-08-20 00:33:05 +02:00
$q = $stmt -> execute ([
$msgid ,
$from ,
$to ,
$target ,
$date ,
$subject ,
$message ,
null ,
null ,
false ,
false
]);
2023-08-09 19:10:35 +02:00
$dbh = null ;
return true ;
}
2024-02-02 18:20:37 +01:00
2024-03-04 17:47:34 +01:00
function delete_message ( $messageid , $group = null , $overview_dbh = null )
2024-01-29 13:33:12 +01:00
{
global $logfile , $config_dir , $spooldir , $CONFIG , $webserver_group ;
2024-03-04 17:47:34 +01:00
if ( $group == null ) {
2024-03-01 21:08:21 +01:00
$message = get_data_from_msgid ( $messageid );
$groups = $message [ 'newsgroup' ];
$grouplist = preg_split ( " /( | \ ,)/ " , $groups );
} else {
$grouplist [ 0 ] = $group ;
}
2024-03-04 17:47:34 +01:00
2024-01-29 13:33:12 +01:00
/* Find section */
$menulist = file ( $config_dir . " menu.conf " , FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES );
2024-03-04 17:47:34 +01:00
foreach ( $grouplist as $group ) {
foreach ( $menulist as $menu ) {
if ( $menu [ 0 ] == '#' ) {
continue ;
}
$menuitem = explode ( ':' , $menu );
$glfp = fopen ( $config_dir . $menuitem [ 0 ] . " /groups.txt " , 'r' );
while ( $gl = fgets ( $glfp )) {
$group_name = preg_split ( " /( | \t )/ " , $gl , 2 );
if ( strtolower ( trim ( $group )) == strtolower ( trim ( $group_name [ 0 ]))) {
$config_name = $menuitem [ 0 ];
// echo "\nFOUND: " . $group . " IN: " . $config_name;
file_put_contents ( $logfile , " \n " . format_log_date () . " " . $config_name . " FOUND: " . $group . " IN: " . $config_name , FILE_APPEND );
break 2 ;
}
}
2024-01-29 13:33:12 +01:00
}
2024-03-04 17:47:34 +01:00
if ( $CONFIG [ 'article_database' ] == '1' ) {
$database = $spooldir . '/' . $group . '-articles.db3' ;
if ( is_file ( $database )) {
$articles_dbh = article_db_open ( $database );
$articles_stmt = $articles_dbh -> prepare ( 'DELETE FROM articles WHERE msgid=:messageid' );
$articles_stmt -> execute ([
'messageid' => $messageid
]);
$articles_dbh = null ;
2024-01-29 13:33:12 +01:00
}
}
2024-03-04 17:47:34 +01:00
// Handle overview and history
if ( $overview_dbh == null ) {
$database = $spooldir . '/articles-overview.db3' ;
$overview_dbh = overview_db_open ( $database );
if ( ! $overview_dbh ) {
file_put_contents ( $logfile , " \n " . format_log_date () . " " . $config_name . " FAILED opening " . $database , FILE_APPEND );
return ;
}
$close_ovdb = true ;
}
$overview_stmt_del = $overview_dbh -> prepare ( 'DELETE FROM overview WHERE newsgroup=:newsgroup AND msgid=:msgid' );
$overview_query = $overview_dbh -> prepare ( 'SELECT * FROM overview WHERE newsgroup=:newsgroup AND msgid=:msgid' );
$overview_query -> execute ([
2024-01-29 13:33:12 +01:00
':newsgroup' => $group ,
':msgid' => $messageid
]);
2024-03-04 17:47:34 +01:00
$grouppath = preg_replace ( '/\./' , '/' , $group );
$status = " deleted " ;
$statusdate = time ();
$statusreason = " nocem " ;
$statusnotes = null ;
while ( $row = $overview_query -> fetch ()) {
if ( isset ( $row [ 'number' ])) {
// echo "\nFOUND: " . $messageid . " IN: " . $group;
file_put_contents ( $logfile , " \n " . format_log_date () . " " . $config_name . " DELETING: " . $messageid . " IN: " . $group , FILE_APPEND );
}
if ( is_file ( $spooldir . '/articles/' . $grouppath . '/' . $row [ 'number' ])) {
unlink ( $spooldir . '/articles/' . $grouppath . '/' . $row [ 'number' ]);
}
delete_message_from_overboard ( $config_name , $group , $messageid );
add_to_history ( $group , $row [ 'number' ], $row [ 'msgid' ], $status , $statusdate , $statusreason , $statusnotes );
thread_cache_removearticle ( $group , $row [ 'number' ]);
$overview_stmt_del -> execute ([
':newsgroup' => $group ,
':msgid' => $messageid
]);
}
}
if ( $close_ovdb ) {
$overview_dbh = null ;
2024-01-29 13:33:12 +01:00
}
return ;
}
2024-03-01 21:08:21 +01:00
// This function returns FALSE if article is OK
// Else returns a string with reason for failure
2024-03-04 17:47:34 +01:00
function check_article_integrity ( $rawmessage )
{
2024-03-01 21:08:21 +01:00
global $CONFIG , $logfile ;
$returnval = false ;
$count_rawmessage = count ( $rawmessage );
$message = new messageType ();
$rawheader = array ();
$i = 0 ;
while ( $rawmessage [ $i ] != " " ) {
$rawheader [] = $rawmessage [ $i ];
$i ++ ;
}
// Parse the Header:
$message -> header = parse_header ( $rawheader );
// Now we know if the message is a mime-multipart message:
$content_type = explode ( " / " , $message -> header -> content_type [ 0 ]);
if ( $content_type [ 0 ] == " multipart " ) {
$message -> header -> content_type = array ();
// We have multible bodies, so we split the message into its parts
$boundary = " -- " . $message -> header -> content_type_boundary ;
// lets find the first part
while ( $rawmessage [ $i ] != $boundary ) {
$i ++ ;
2024-03-04 17:47:34 +01:00
if ( $i > $count_rawmessage ) {
2024-03-01 21:08:21 +01:00
$returnval = " Skipping malformed message: " . $message -> header -> id ;
return $returnval ;
}
}
}
return $returnval ;
}
2024-01-29 13:33:12 +01:00
function delete_message_from_overboard ( $config_name , $group , $messageid )
{
GLOBAL $spooldir ;
$cachefile = $spooldir . " / " . $config_name . " -overboard.dat " ;
if ( is_file ( $cachefile )) {
$cached_overboard = unserialize ( file_get_contents ( $cachefile ));
if ( $target = $cached_overboard [ 'msgids' ][ $messageid ]) {
unset ( $cached_overboard [ 'threads' ][ $target [ 'date' ]]);
unset ( $cached_overboard [ 'msgids' ][ $messageid ]);
unset ( $cached_overboard [ 'threadlink' ][ $messageid ]);
file_put_contents ( $cachefile , serialize ( $cached_overboard ));
}
}
$cachefile = $spooldir . " / " . $group . " -overboard.dat " ;
if ( is_file ( $cachefile )) {
$cached_overboard = unserialize ( file_get_contents ( $cachefile ));
if ( $target = $cached_overboard [ 'msgids' ][ $messageid ]) {
unset ( $cached_overboard [ 'threads' ][ $target [ 'date' ]]);
unset ( $cached_overboard [ 'msgids' ][ $messageid ]);
unset ( $cached_overboard [ 'threadlink' ][ $messageid ]);
file_put_contents ( $cachefile , serialize ( $cached_overboard ));
}
}
2024-03-02 04:03:16 +01:00
}