/**
* Copyright ( C ) 2014 - 2015 Jessica James .
*
* Permission to use , copy , modify , and / or distribute this software for any
* purpose with or without fee is hereby granted , provided that the above
* copyright notice and this permission notice appear in all copies .
*
* THE SOFTWARE IS PROVIDED " AS IS " AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS . IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL , DIRECT , INDIRECT , OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE , DATA OR PROFITS , WHETHER IN AN ACTION
* OF CONTRACT , NEGLIGENCE OR OTHER TORTIOUS ACTION , ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE .
*
* Written by Jessica James < jessica . aj @ outlook . com >
*/
# include <cstdio>
# include "Jupiter/IRC_Client.h"
# include "Jupiter/INIFile.h"
# include "RenX_PlayerInfo.h"
# include "RenX_BanDatabase.h"
# include "RenX_Core.h"
# include "RenX_Plugin.h"
using namespace Jupiter : : literals ;
RenX : : BanDatabase _banDatabase ;
RenX : : BanDatabase * RenX : : banDatabase = & _banDatabase ;
RenX : : BanDatabase & RenX : : defaultBanDatabase = _banDatabase ;
const Jupiter : : ReferenceString DEFAULT_REASON = " (No reason information provided) " ;
const uint8_t write_version = 2U ;
bool RenX : : BanDatabase : : load ( const Jupiter : : ReadableString & fname )
{
RenX : : BanDatabase : : filename = fname ;
FILE * file = fopen ( RenX : : BanDatabase : : filename . c_str ( ) , " rb " ) ;
if ( file ! = nullptr )
{
RenX : : BanDatabase : : version = fgetc ( file ) ;
while ( ! feof ( file ) )
if ( fgetc ( file ) = = ' \n ' )
break ;
Jupiter : : String rdns ( 128 ) ;
Jupiter : : String playerName ( 16 ) ;
Jupiter : : String key ( 32 ) ;
Jupiter : : String value ( 32 ) ;
Jupiter : : String reason ( 128 ) ;
if ( RenX : : BanDatabase : : version = = 0 )
reason = DEFAULT_REASON ;
Entry * entry ;
int c ;
while ( ! feof ( file ) )
{
entry = new Entry ( ) ;
fgetpos ( file , & entry - > pos ) ;
fread ( & entry - > active , 1 , 1 , file ) ;
fread ( & entry - > timestamp , sizeof ( time_t ) , 1 , file ) ;
fread ( & entry - > length , sizeof ( time_t ) , 1 , file ) ;
fread ( & entry - > steamid , sizeof ( uint64_t ) , 1 , file ) ;
fread ( & entry - > ip , sizeof ( uint32_t ) , 1 , file ) ;
if ( feof ( file ) )
{
delete entry ;
break ;
}
// load rdns
if ( RenX : : BanDatabase : : version > = 2 )
{
rdns . truncate ( rdns . size ( ) ) ;
c = fgetc ( file ) ;
while ( c ! = ' \n ' & & c ! = ' \0 ' )
{
if ( c = = EOF )
{
fprintf ( stderr , " ERROR: Unexpected EOF in %s at %lu " , RenX : : BanDatabase : : filename . c_str ( ) , ftell ( file ) ) ;
break ;
}
rdns + = c ;
c = fgetc ( file ) ;
}
entry - > rdns = rdns ;
}
// load name
playerName . truncate ( playerName . size ( ) ) ;
c = fgetc ( file ) ;
while ( c ! = ' \n ' & & c ! = ' \0 ' )
{
if ( c = = EOF )
{
fprintf ( stderr , " ERROR: Unexpected EOF in %s at %lu " , RenX : : BanDatabase : : filename . c_str ( ) , ftell ( file ) ) ;
break ;
}
playerName + = c ;
c = fgetc ( file ) ;
}
entry - > name = playerName ;
// load reason
if ( RenX : : BanDatabase : : version > = 1 )
{
reason . truncate ( reason . size ( ) ) ;
c = fgetc ( file ) ;
while ( c ! = ' \n ' & & c ! = ' \0 ' )
{
if ( c = = EOF )
{
fprintf ( stderr , " ERROR: Unexpected EOF in %s at %lu " , RenX : : BanDatabase : : filename . c_str ( ) , ftell ( file ) ) ;
break ;
}
reason + = c ;
c = fgetc ( file ) ;
}
}
entry - > reason = reason ;
// load variable data
while ( c = = ' \0 ' )
{
key . truncate ( key . size ( ) ) ;
value . truncate ( value . size ( ) ) ;
// load key
c = fgetc ( file ) ;
while ( c ! = ' \0 ' & & c ! = EOF )
{
key + = c ;
c = fgetc ( file ) ;
}
if ( c = = EOF )
{
fprintf ( stderr , " ERROR: Unexpected EOF in %s at %lu " , RenX : : BanDatabase : : filename . c_str ( ) , ftell ( file ) ) ;
break ;
}
// load value
c = fgetc ( file ) ;
while ( c ! = ' \n ' & & c ! = ' \0 ' & & c ! = EOF )
{
value + = c ;
c = fgetc ( file ) ;
}
if ( c = = EOF )
{
fprintf ( stderr , " ERROR: Unexpected EOF in %s at %lu " , RenX : : BanDatabase : : filename . c_str ( ) , ftell ( file ) ) ;
break ;
}
entry - > varData . set ( key , value ) ;
}
entries . add ( entry ) ;
}
fclose ( file ) ;
if ( RenX : : BanDatabase : : version ! = write_version )
{
file = fopen ( RenX : : BanDatabase : : filename . c_str ( ) , " wb " ) ;
if ( file ! = nullptr )
{
fputc ( write_version , file ) ;
fputc ( ' \n ' , file ) ;
size_t index = 0 ;
while ( index ! = RenX : : BanDatabase : : entries . size ( ) )
RenX : : BanDatabase : : write ( RenX : : BanDatabase : : entries . get ( + + index ) , file ) ;
fclose ( file ) ;
fprintf ( stdout , " Updated BanDatabase file \" %s \" from version %d to %d. " ENDL , RenX : : BanDatabase : : filename . c_str ( ) , RenX : : BanDatabase : : version , write_version ) ;
}
else
fprintf ( stdout , " CRITICAL ERROR: BanDatabase file \" %s \" failed to update from version %d to %d. " ENDL , RenX : : BanDatabase : : filename . c_str ( ) , RenX : : BanDatabase : : version , write_version ) ;
RenX : : BanDatabase : : version = write_version ;
}
return true ;
}
else
{
RenX : : BanDatabase : : version = write_version ;
file = fopen ( RenX : : BanDatabase : : filename . c_str ( ) , " ab " ) ;
if ( file ! = nullptr )
{
fputc ( RenX : : BanDatabase : : version , file ) ;
fputc ( ' \n ' , file ) ;
fclose ( file ) ;
return true ;
}
return false ;
}
}
void RenX : : BanDatabase : : write ( RenX : : BanDatabase : : Entry * entry )
{
if ( RenX : : BanDatabase : : version ! = write_version )
" CRITICAL ERROR: COULD NOT WRITE BAN ENTRY TO BAN DATABASE (VERSION MISMATCH) " _jrs . print ( stdout ) ;
FILE * file = fopen ( RenX : : BanDatabase : : filename . c_str ( ) , " ab " ) ;
if ( file ! = nullptr )
{
RenX : : BanDatabase : : write ( entry , file ) ;
fclose ( file ) ;
}
}
void RenX : : BanDatabase : : write ( RenX : : BanDatabase : : Entry * entry , FILE * file )
{
fgetpos ( file , & entry - > pos ) ;
fwrite ( & entry - > active , 1 , 1 , file ) ;
fwrite ( & entry - > timestamp , sizeof ( time_t ) , 1 , file ) ;
fwrite ( & entry - > length , sizeof ( time_t ) , 1 , file ) ;
fwrite ( & entry - > steamid , sizeof ( uint64_t ) , 1 , file ) ;
fwrite ( & entry - > ip , sizeof ( uint32_t ) , 1 , file ) ;
fwrite ( entry - > rdns . ptr ( ) , sizeof ( char ) , entry - > rdns . size ( ) , file ) ;
fputc ( ' \0 ' , file ) ;
fwrite ( entry - > name . ptr ( ) , sizeof ( char ) , entry - > name . size ( ) , file ) ;
fputc ( ' \0 ' , file ) ;
fwrite ( entry - > reason . ptr ( ) , sizeof ( char ) , entry - > reason . size ( ) , file ) ;
for ( size_t index = 0 ; index ! = entry - > varData . size ( ) ; + + index )
{
const Jupiter : : INIFile : : Section : : KeyValuePair * pair = entry - > varData . getPair ( index ) ;
fputc ( ' \0 ' , file ) ;
fwrite ( pair - > getKey ( ) . ptr ( ) , sizeof ( char ) , pair - > getKey ( ) . size ( ) , file ) ;
fputc ( ' \0 ' , file ) ;
fwrite ( pair - > getValue ( ) . ptr ( ) , sizeof ( char ) , pair - > getValue ( ) . size ( ) , file ) ;
}
fputc ( ' \n ' , file ) ;
}
void RenX : : BanDatabase : : add ( RenX : : Server * server , const RenX : : PlayerInfo * player , const Jupiter : : ReadableString & reason , time_t length )
{
Entry * entry = new Entry ( ) ;
entry - > active = 1 ;
entry - > timestamp = time ( 0 ) ;
entry - > length = length ;
entry - > steamid = player - > steamid ;
entry - > ip = player - > ip32 ;
entry - > rdns = player - > rdns ;
entry - > name = player - > name ;
entry - > reason = reason ;
// add plugin data
Jupiter : : String pluginData ;
Jupiter : : ArrayList < RenX : : Plugin > & xPlugins = * RenX : : getCore ( ) - > getPlugins ( ) ;
for ( size_t i = 0 ; i < xPlugins . size ( ) ; i + + )
if ( xPlugins . get ( i ) - > RenX_OnBan ( server , player , pluginData ) )
entry - > varData . set ( xPlugins . get ( i ) - > getName ( ) , pluginData ) ;
entries . add ( entry ) ;
RenX : : BanDatabase : : write ( entry ) ;
}
bool RenX : : BanDatabase : : deactivate ( size_t index )
{
RenX : : BanDatabase : : Entry * entry = RenX : : BanDatabase : : entries . get ( index ) ;
if ( entry - > active )
{
entry - > active = 0 ;
FILE * file = fopen ( RenX : : BanDatabase : : filename . c_str ( ) , " r+b " ) ;
if ( file ! = nullptr )
{
fsetpos ( file , & entry - > pos ) ;
fputc ( entry - > active , file ) ;
fclose ( file ) ;
}
return true ;
}
return false ;
}
uint8_t RenX : : BanDatabase : : getVersion ( ) const
{
return RenX : : BanDatabase : : version ;
}
const Jupiter : : ReadableString & RenX : : BanDatabase : : getFileName ( ) const
{
return RenX : : BanDatabase : : filename ;
}
const Jupiter : : ArrayList < RenX : : BanDatabase : : Entry > & RenX : : BanDatabase : : getEntries ( ) const
{
return RenX : : BanDatabase : : entries ;
}
RenX : : BanDatabase : : BanDatabase ( )
{
RenX : : BanDatabase : : load ( Jupiter : : IRC : : Client : : Config - > get ( STRING_LITERAL_AS_REFERENCE ( " RenX " ) , STRING_LITERAL_AS_REFERENCE ( " BanDB " ) , STRING_LITERAL_AS_REFERENCE ( " Bans.db " ) ) ) ;
}
RenX : : BanDatabase : : ~ BanDatabase ( )
{
RenX : : BanDatabase : : entries . emptyAndDelete ( ) ;
}