From 067841db3f3ea4a8bf93580e42945d73fc81f14b Mon Sep 17 00:00:00 2001 From: "M. Kristall" Date: Wed, 20 Oct 2010 05:55:52 +0000 Subject: * (bug 3495) Add support for message censorship (cue "finally!") --- src/game/g_client.c | 4 +- src/game/g_cmds.c | 159 ++++++++++++++++++++++++++++++++++++++++++++++++++-- src/game/g_local.h | 4 ++ src/game/g_main.c | 5 ++ src/game/g_svcmds.c | 1 + 5 files changed, 167 insertions(+), 6 deletions(-) (limited to 'src/game') diff --git a/src/game/g_client.c b/src/game/g_client.c index 0bf70230..2ac76c73 100644 --- a/src/game/g_client.c +++ b/src/game/g_client.c @@ -1061,8 +1061,8 @@ char *ClientUserinfoChanged( int clientNum, qboolean forceName ) } else { - Q_strncpyz( client->pers.netname, newname, - sizeof( client->pers.netname ) ); + G_CensorString( client->pers.netname, newname, + sizeof( client->pers.netname ), ent ); if( !forceName && client->pers.connected == CON_CONNECTED ) { client->pers.namelog->nameChangeTime = level.time; diff --git a/src/game/g_cmds.c b/src/game/g_cmds.c index 390c6a5b..13d27f4f 100644 --- a/src/game/g_cmds.c +++ b/src/game/g_cmds.c @@ -642,6 +642,152 @@ void Cmd_Team_f( gentity_t *ent ) G_ChangeTeam( ent, team ); } +/* +================== +G_CensorString +================== +*/ +static char censors[ 20000 ]; +static int numcensors; + +void G_LoadCensors( void ) +{ + char *text_p, *token; + char text[ 20000 ]; + char *term; + int len; + fileHandle_t f; + + numcensors = 0; + + if( !g_censorship.string[ 0 ] ) + return; + + len = trap_FS_FOpenFile( g_censorship.string, &f, FS_READ ); + if( len < 0 ) + { + Com_Printf( S_COLOR_RED "ERROR: Censors file %s doesn't exist\n", + g_censorship.string ); + return; + } + if( len == 0 || len >= sizeof( text ) - 1 ) + { + trap_FS_FCloseFile( f ); + Com_Printf( S_COLOR_RED "ERROR: Censors file %s is %s\n", + g_censorship.string, len == 0 ? "empty" : "too long" ); + return; + } + trap_FS_Read( text, len, f ); + trap_FS_FCloseFile( f ); + text[ len ] = 0; + + term = censors; + + text_p = text; + while( 1 ) + { + token = COM_Parse( &text_p ); + if( !*token || sizeof( censors ) - ( term - censors ) < 4 ) + break; + Q_strncpyz( term, token, sizeof( censors ) - ( term - censors ) ); + Q_strlwr( term ); + term += strlen( term ) + 1; + if( sizeof( censors ) - ( term - censors ) == 0 ) + break; + token = COM_ParseExt( &text_p, qfalse ); + Q_strncpyz( term, token, sizeof( censors ) - ( term - censors ) ); + term += strlen( term ) + 1; + numcensors++; + } + G_Printf( "Parsed %d string replacements\n", numcensors ); +} + +void G_CensorString( char *out, const char *in, int len, gentity_t *ent ) +{ + const char *s, *m; + int i; + + if( !numcensors || G_admin_permission( ent, ADMF_NOCENSORFLOOD) ) + { + Q_strncpyz( out, in, len ); + return; + } + + len--; + while( *in ) + { + if( Q_IsColorString( in ) ) + { + if( len < 2 ) + break; + *out++ = *in++; + *out++ = *in++; + len -= 2; + continue; + } + if( !isalnum( *in ) ) + { + if( len < 1 ) + break; + *out++ = *in++; + len--; + continue; + } + m = censors; + for( i = 0; i < numcensors; i++, m++ ) + { + s = in; + while( *s && *m ) + { + if( Q_IsColorString( s ) ) + { + s += 2; + continue; + } + if( !isalnum( *s ) ) + { + s++; + continue; + } + if( tolower( *s ) != *m ) + break; + s++; + m++; + } + // match + if( !*m ) + { + in = s; + m++; + while( *m ) + { + if( len < 1 ) + break; + *out++ = *m++; + len--; + } + break; + } + else + { + while( *m ) + m++; + m++; + while( *m ) + m++; + } + } + if( len < 1 ) + break; + // no match + if( i == numcensors ) + { + *out++ = *in++; + len--; + } + } + *out = 0; +} /* ================== @@ -720,7 +866,7 @@ void G_Say( gentity_t *ent, saymode_t mode, const char *chatText ) break; } - Q_strncpyz( text, chatText, sizeof( text ) ); + G_CensorString( text, chatText, sizeof( text ), ent ); // send it to all the apropriate clients for( j = 0; j < level.maxclients; j++ ) @@ -807,6 +953,7 @@ Cmd_VSay_f void Cmd_VSay_f( gentity_t *ent ) { char arg[MAX_TOKEN_CHARS]; + char text[ MAX_TOKEN_CHARS ]; voiceChannel_t vchan; voice_t *voice; voiceCmd_t *cmd; @@ -900,6 +1047,7 @@ void Cmd_VSay_f( gentity_t *ent ) // optional user supplied text trap_Argv( 2, arg, sizeof( arg ) ); + G_CensorString( text, arg, sizeof( text ), ent ); switch( vchan ) { @@ -907,12 +1055,12 @@ void Cmd_VSay_f( gentity_t *ent ) case VOICE_CHAN_LOCAL: trap_SendServerCommand( -1, va( "voice %d %d %d %d \"%s\"\n", - ent-g_entities, vchan, cmdNum, trackNum, arg ) ); + ent-g_entities, vchan, cmdNum, trackNum, text ) ); break; case VOICE_CHAN_TEAM: G_TeamCommand( ent->client->pers.teamSelection, va( "voice %d %d %d %d \"%s\"\n", - ent-g_entities, vchan, cmdNum, trackNum, arg ) ); + ent-g_entities, vchan, cmdNum, trackNum, text ) ); break; default: break; @@ -3035,6 +3183,7 @@ void Cmd_PrivateMessage_f( gentity_t *ent ) char name[ MAX_NAME_LENGTH ]; char cmd[ 12 ]; char str[ MAX_STRING_CHARS ]; + char text[ MAX_STRING_CHARS ]; char *msg; char color; int i, pcount; @@ -3073,12 +3222,14 @@ void Cmd_PrivateMessage_f( gentity_t *ent ) Com_sprintf( str, sizeof( str ), "^%csent to %i player%s", color, count, ( count == 1 ) ? "" : "s" ); + G_CensorString( text, msg, sizeof( text ), ent ); + if( !count ) ADMP( va( "^3No player matching ^7\'%s^7\' ^3to send message to.\n", name ) ); else { - ADMP( va( "^%cPrivate message: ^7%s\n", color, msg ) ); + ADMP( va( "^%cPrivate message: ^7%s\n", color, text ) ); ADMP( va( "%s\n", str ) ); G_LogPrintf( "%s: %d \"%s" S_COLOR_WHITE "\" \"%s\": ^%c%s\n", diff --git a/src/game/g_local.h b/src/game/g_local.h index a6fff69b..7aaf3bf4 100644 --- a/src/game/g_local.h +++ b/src/game/g_local.h @@ -722,6 +722,8 @@ void Cmd_Test_f( gentity_t *ent ); void Cmd_AdminMessage_f( gentity_t *ent ); int G_FloodLimited( gentity_t *ent ); void G_ListCommands( gentity_t *ent ); +void G_LoadCensors( void ); +void G_CensorString( char *out, const char *in, int len, gentity_t *ent ); // // g_physics.c @@ -1157,6 +1159,8 @@ extern vmCvar_t g_specChat; extern vmCvar_t g_publicAdminMessages; extern vmCvar_t g_allowTeamOverlay; +extern vmCvar_t g_censorship; + void trap_Print( const char *fmt ); void trap_Error( const char *fmt ); int trap_Milliseconds( void ); diff --git a/src/game/g_main.c b/src/game/g_main.c index b5d409f1..bdc948e1 100644 --- a/src/game/g_main.c +++ b/src/game/g_main.c @@ -133,6 +133,8 @@ vmCvar_t g_specChat; vmCvar_t g_publicAdminMessages; vmCvar_t g_allowTeamOverlay; +vmCvar_t g_censorship; + vmCvar_t g_tag; static cvarTable_t gameCvarTable[ ] = @@ -254,6 +256,8 @@ static cvarTable_t gameCvarTable[ ] = { &g_publicAdminMessages, "g_publicAdminMessages", "1", CVAR_ARCHIVE, 0, qfalse }, { &g_allowTeamOverlay, "g_allowTeamOverlay", "1", CVAR_ARCHIVE, 0, qtrue }, + { &g_censorship, "g_censorship", "", CVAR_ARCHIVE, 0, qfalse }, + { &g_tag, "g_tag", "main", CVAR_INIT, 0, qfalse } }; @@ -559,6 +563,7 @@ void G_InitGame( int levelTime, int randomSeed, int restart ) G_RegisterCommands( ); G_admin_readconfig( NULL ); + G_LoadCensors( ); // initialize all entities for this game memset( g_entities, 0, MAX_GENTITIES * sizeof( g_entities[ 0 ] ) ); diff --git a/src/game/g_svcmds.c b/src/game/g_svcmds.c index fc4dad45..3d89ef47 100644 --- a/src/game/g_svcmds.c +++ b/src/game/g_svcmds.c @@ -542,6 +542,7 @@ struct svcmd { "listmaps", qtrue, Svcmd_ListMapsWrapper }, { "m", qtrue, Svcmd_MessageWrapper }, { "mapRotation", qfalse, Svcmd_MapRotation_f }, + { "loadcensors", qfalse, G_LoadCensors }, { "printqueue", qfalse, Svcmd_PrintQueue_f }, { "say", qtrue, Svcmd_MessageWrapper }, { "say_team", qtrue, Svcmd_TeamMessage_f }, -- cgit