summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/game/g_client.c4
-rw-r--r--src/game/g_cmds.c159
-rw-r--r--src/game/g_local.h4
-rw-r--r--src/game/g_main.c5
-rw-r--r--src/game/g_svcmds.c1
5 files changed, 167 insertions, 6 deletions
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 },