diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/game/g_admin.c | 243 | ||||
| -rw-r--r-- | src/game/g_admin.h | 15 | ||||
| -rw-r--r-- | src/game/g_client.c | 80 | ||||
| -rw-r--r-- | src/game/g_cmds.c | 10 | ||||
| -rw-r--r-- | src/game/g_local.h | 5 | ||||
| -rw-r--r-- | src/game/g_main.c | 13 | ||||
| -rw-r--r-- | src/game/g_svcmds.c | 30 | 
7 files changed, 389 insertions, 7 deletions
diff --git a/src/game/g_admin.c b/src/game/g_admin.c index 45c37e4..dc19530 100644 --- a/src/game/g_admin.c +++ b/src/game/g_admin.c @@ -421,6 +421,11 @@ g_admin_cmd_t g_admin_cmds[ ] =      {"tklog", G_admin_tklog, "tklog",        "list recent teamkill activity",        "(^5start id#|name|-skip#^7) (^5search skip#^7)" +    }, + +    {"sm", G_admin_sm, "schachtmeister", +      "Schachtmeister", +      "..."      }    }; @@ -1471,6 +1476,9 @@ qboolean G_admin_cmd_check( gentity_t *ent, qboolean say )      return qtrue;     } +  if( G_admin_is_restricted( ent, qtrue ) ) +    return qtrue; +    for( i = 0; i < MAX_ADMIN_COMMANDS && g_admin_commands[ i ]; i++ )    {      if( Q_stricmp( cmd, g_admin_commands[ i ]->command ) ) @@ -1519,11 +1527,49 @@ void G_admin_namelog_cleanup( )    for( i = 0; i < MAX_ADMIN_NAMELOGS && g_admin_namelog[ i ]; i++ )    { +    if( g_admin_namelog[ i ]->smj.comment ) +      G_Free( g_admin_namelog[ i ]->smj.comment );      G_Free( g_admin_namelog[ i ] );      g_admin_namelog[ i ] = NULL;    }  } +static void dispatchSchachtmeisterIPAQuery( const char *ipa ) +{ +  trap_SendConsoleCommand( EXEC_APPEND, va( "smq ipa \"%s\"\n", ipa ) ); +} + +static void schachtmeisterProcess( g_admin_namelog_t *namelog ) +{ +  schachtmeisterJudgement_t *j = &namelog->smj; + +  if( !j->ratingTime || level.time - j->ratingTime >= 600000 ) +  { +    if( j->queryTime ) +      return; + +    j->queryTime = level.time; +    goto dispatch; +  } + +  if( !j->queryTime || level.time - j->queryTime >= 60000 ) +    return; + +  if( j->dispatchTime && level.time - j->dispatchTime < 5000 ) +    return; + +  dispatch: +  j->dispatchTime = level.time; +  dispatchSchachtmeisterIPAQuery( namelog->ip ); +} + +void G_admin_schachtmeisterFrame( void ) +{ +  int i; +  for( i = 0; i < MAX_ADMIN_NAMELOGS && g_admin_namelog[ i ]; i++ ) +    schachtmeisterProcess( g_admin_namelog[ i ] ); +} +  void G_admin_namelog_update( gclient_t *client, qboolean disconnect )  {    int i, j; @@ -1659,6 +1705,7 @@ void G_admin_namelog_update( gclient_t *client, qboolean disconnect )    Q_strncpyz( namelog->name[ 0 ], client->pers.netname,      sizeof( namelog->name[ 0 ] ) );    namelog->slot = ( disconnect ) ? -1 : clientNum; +  schachtmeisterProcess( namelog );    g_admin_namelog[ i ] = namelog;  } @@ -2370,7 +2417,8 @@ static AdminFlagListEntry_t adminFlagList[] =    { ADMF_NOSCRIMRESTRICTION,   "team joining, vote and chat restrictions during scrims do not apply" },    { ADMF_NO_BUILD,             "can not build" },    { ADMF_NO_CHAT,              "can not talk" }, -  { ADMF_NO_VOTE,              "can not call votes" } +  { ADMF_NO_VOTE,              "can not call votes" }, +  { ADMF_NOAUTOBAHN,           "ignored by the Autobahn system" }  };  static int adminNumFlags= sizeof( adminFlagList ) / sizeof( adminFlagList[ 0 ] ); @@ -2930,6 +2978,102 @@ qboolean G_admin_ban( gentity_t *ent, int skiparg )    return qtrue;  } +// If true then don't let the player join a team, use the chat or run commands. +qboolean G_admin_is_restricted(gentity_t *ent, qboolean sendMessage) +{ +	schachtmeisterJudgement_t *j = NULL; +	int i; + +	// Never restrict admins or whitelisted players. +	if (G_admin_permission(ent, ADMF_NOAUTOBAHN) || +	    G_admin_permission(ent, ADMF_IMMUNITY)) +		return qfalse; + +	// Find the relevant namelog. +	// FIXME: this shouldn't require looping over *all* namelogs. +	for (i = 0; i < MAX_ADMIN_NAMELOGS && g_admin_namelog[i]; i++) { +		if (g_admin_namelog[i]->slot == ent - g_entities) { +			j = &g_admin_namelog[i]->smj; +			break; +		} +	} + +	// A missing namelog shouldn't happen. +	if (!j) +		return qfalse; + +	// Restrictions concern only unrated players. +	if (j->ratingTime) +		return qfalse; + +	// Don't wait forever, allow up to 15 seconds. +	if (level.time - j->queryTime >= 15000) +		return qfalse; + +	if (sendMessage) +		trap_SendServerCommand(ent - g_entities, "print \"Please wait a moment before doing anything.\n\""); + +	return qtrue; +} + +static void admin_autobahn(gentity_t *ent, int rating) +{ +	// Allow per-GUID exceptions and never autoban admins. +	if (G_admin_permission(ent, ADMF_NOAUTOBAHN) || +	    G_admin_permission(ent, ADMF_IMMUNITY)) +		return; + +	// Don't do anything if the rating is clear. +	if (rating >= g_schachtmeisterClearThreshold.integer) +		return; + +	// Ban only if the rating is low enough. +	if (rating > g_schachtmeisterAutobahnThreshold.integer) { +		G_AdminsPrintf("%s^7 (#%d) has rating %d\n", +		               ent->client->pers.netname, ent - g_entities, +		               rating); +		return; +	} + +	G_LogAutobahn(ent, NULL, rating, qfalse); + +	trap_SendServerCommand(ent - g_entities, va("disconnect \"%s\"\n", +	                       g_schachtmeisterAutobahnMessage.string)); +	trap_DropClient(ent - g_entities, "dropped by the Autobahn"); +} + +void G_admin_IPA_judgement( const char *ipa, int rating, const char *comment ) +{ +  int i; +  for( i = 0; i < MAX_ADMIN_NAMELOGS && g_admin_namelog[ i ]; i++ ) +  { +    if( !strcmp( g_admin_namelog[ i ]->ip, ipa ) ) +    { +      schachtmeisterJudgement_t *j = &g_admin_namelog[ i ]->smj; + +      j->ratingTime = level.time; +      j->queryTime = 0; +      j->dispatchTime = 0; + +      j->rating = rating; + +      if( j->comment ) +        G_Free( j->comment ); + +      if( comment ) +      { +        j->comment = G_Alloc( strlen( comment ) + 1 ); +        strcpy( j->comment, comment ); +      } +      else +        j->comment = NULL; + +      if( g_admin_namelog[ i ]->slot != -1 ) +        admin_autobahn( g_entities + g_admin_namelog[ i ]->slot, j->rating ); +    } +  } +} +  qboolean G_admin_adjustban( gentity_t *ent, int skiparg )  {    int bnum; @@ -6121,6 +6265,35 @@ qboolean G_admin_nextmap( gentity_t *ent, int skiparg )    return qtrue;  } +static const char *displaySchachtmeisterJudgement(const schachtmeisterJudgement_t *j, +                                                  g_admin_namelog_t *namelog) +{ +	static char buffer[20]; + +    if (G_admin_permission_guid(namelog->guid, ADMF_INCOGNITO)) { +	    Com_sprintf(buffer, sizeof(buffer), "^2   +0"); +    } else if (strcmp(namelog->guid, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX") && +	    (G_admin_permission_guid(namelog->guid, ADMF_NOAUTOBAHN) || +	     G_admin_permission_guid(namelog->guid, ADMF_IMMUNITY))) { +		Com_sprintf(buffer, sizeof(buffer), "^7 N/A "); +	} else if (!j->ratingTime) { +		Com_sprintf(buffer, sizeof(buffer), "^5 wait"); +	} else { +		int color; + +		if (j->rating >= g_schachtmeisterClearThreshold.integer) +			color = 2; +		else if (j->rating <= g_schachtmeisterAutobahnThreshold.integer) +			color = 1; +		else +			color = 3; + +		Com_sprintf(buffer, sizeof(buffer), "^%i%+5i", color, j->rating); +	} + +	return buffer; +} +  qboolean G_admin_namelog( gentity_t *ent, int skiparg )  {    int i, j; @@ -6161,10 +6334,11 @@ qboolean G_admin_namelog( gentity_t *ent, int skiparg )      guid_stub[ j ] = '\0';      if( g_admin_namelog[ i ]->slot > -1 )         ADMBP( "^3" ); -    ADMBP( va( "%-2s (*%s) %15s^7",  +    ADMBP( va( "%-2s (*%s) %15s %s^7",         (g_admin_namelog[ i ]->slot > -1 ) ?          va( "%d", g_admin_namelog[ i ]->slot ) : "-", -      guid_stub, g_admin_namelog[ i ]->ip ) ); +      guid_stub, g_admin_namelog[ i ]->ip, +      displaySchachtmeisterJudgement( &g_admin_namelog[ i ]->smj, g_admin_namelog[ i ] ) ) );      for( j = 0; j < MAX_ADMIN_NAMELOG_NAMES &&         g_admin_namelog[ i ]->name[ j ][ 0 ]; j++ )      { @@ -8185,3 +8359,66 @@ qboolean G_admin_tklog( gentity_t *ent, int skiparg )    return qtrue;  } + +qboolean G_admin_sm( gentity_t *ent, int skiparg ) +{ +  const char *s; +  char feature[ 16 ]; + +  if( G_SayArgc() < 2 + skiparg ) +  { +    usage: +    ADMP( "^3!sm: ^7usage: !sm ipa <IPA>\n" ); +    return qfalse; +  } + +  s = G_SayConcatArgs( 1 + skiparg ); +  if( strchr( s, '\n' ) || strchr( s, '\r' ) ) +  { +    ADMP( "^3!sm: ^7invalid character\n" ); +    return qfalse; +  } + +  G_SayArgv( 1 + skiparg, feature, sizeof( feature ) ); + +  if( !Q_stricmp( feature, "ipa" ) ) +  { +    char ipa[ 32 ]; +    int parts[ 4 ]; + +    if( G_SayArgc() > 3 + skiparg ) +    { +      ADMP( "^3!sm: ^7excessive arguments\n" ); +      goto usage; +    } +    G_SayArgv( 2 + skiparg, ipa, sizeof( ipa ) ); + +    // have a well-formed IPv4 address, because Schachtmeister silently drops all invalid requests + +    if( sscanf( ipa, "%i.%i.%i.%i", &parts[0], &parts[1], &parts[2], &parts[3] ) != 4 +        || parts[0] < 0 || parts[0] > 255 +        || parts[1] < 0 || parts[1] > 255 +        || parts[2] < 0 || parts[2] > 255 +        || parts[3] < 0 || parts[3] > 255 ) +    { +      ADMP( "^3!sm: ^7invalid IP address\n" ); +      return qfalse; +    } + +    Com_sprintf( ipa, sizeof( ipa ), "%i.%i.%i.%i", parts[0], parts[1], parts[2], parts[3] ); + +    if( rand() % 2 /* FIXME cache hit */ ) +    { +      const char *answer = "interesting"; +      ADMP( va( "^3!sm: ^7IP address %s is: %s\n", ipa, answer ) ); +      return qtrue; +    } + +    ADMP( "^3!sm: ^7hmm...\n" ); +    trap_SendConsoleCommand( EXEC_APPEND, va( "smq ipa \"%s\"\n", ipa ) ); +  } +  else +    goto usage; + +  return qtrue; +} diff --git a/src/game/g_admin.h b/src/game/g_admin.h index 3b94644..25cf2a7 100644 --- a/src/game/g_admin.h +++ b/src/game/g_admin.h @@ -100,6 +100,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA  #define ADMF_SPECIALNAME         "SPECIALNAME"  #define ADMF_NOSCRIMRESTRICTION  "NOSCRIMRESTRICTION" +#define ADMF_NOAUTOBAHN          "NOAUTOBAHN"  #define ADMF_NO_BUILD            ".NOBUILD"  #define ADMF_NO_CHAT             ".NOCHAT" @@ -163,6 +164,15 @@ typedef struct g_admin_command  }  g_admin_command_t; +typedef struct +{ +  int ratingTime; +  int queryTime; +  int dispatchTime; +  int rating; +  char *comment; +} schachtmeisterJudgement_t; +  typedef struct g_admin_namelog  {    char      name[ MAX_ADMIN_NAMELOG_NAMES ][MAX_NAME_LENGTH ]; @@ -177,6 +187,7 @@ typedef struct g_admin_namelog    int       denyAlienClasses;    int       specExpires;    int       voteCount; +  schachtmeisterJudgement_t smj;  }  g_admin_namelog_t; @@ -290,6 +301,10 @@ qboolean G_admin_showff(gentity_t *ent, int skiparg);  qboolean G_admin_tklog( gentity_t *ent, int skiparg );  void G_admin_tklog_cleanup( void );  void G_admin_tklog_log( gentity_t *attacker, gentity_t *victim, int meansOfDeath ); +void G_admin_IPA_judgement( const char *ipa, int rating, const char *comment ); +qboolean G_admin_sm( gentity_t *ent, int skiparg ); +void G_admin_schachtmeisterFrame( void ); +qboolean G_admin_is_restricted(gentity_t *ent, qboolean sendMessage);  void G_admin_print( gentity_t *ent, char *m );  void G_admin_buffer_print( gentity_t *ent, char *m ); diff --git a/src/game/g_client.c b/src/game/g_client.c index e488126..c77d4f7 100644 --- a/src/game/g_client.c +++ b/src/game/g_client.c @@ -1377,6 +1377,36 @@ void ClientUserinfoChanged( int clientNum, qboolean forceName )    /*G_LogPrintf( "ClientUserinfoChanged: %i %s\n", clientNum, userinfo );*/  } +/* +=========== +LogAutobahn +=========== +*/ +void G_LogAutobahn(gentity_t *ent, const char *userinfo, int rating, +                   qboolean onConnect) +{ +	char ip_buffer[20]; +	const char *ip, *name, *verb; + +	verb = (onConnect ? "refused" : "dropped"); + +	if (userinfo) { +		Q_strncpyz(ip_buffer, Info_ValueForKey(userinfo, "ip"), +		           sizeof(ip_buffer)); +		ip = ip_buffer; +		name = Info_ValueForKey(userinfo, "name"); +	} else { +		ip = ent->client->pers.ip; +		name = ent->client->pers.netname; +	} + +	G_LogPrintf("Autobahn: %s %i %s %+i \"%s^7\"\n", verb, ent - g_entities, +	            ip, rating, name); + +	if (g_adminAutobahnNotify.integer) +		G_AdminsPrintf("Autobahn %s '%s^7' with rating %+i, connecting from %s.\n", +		               verb, name, rating, ip); +}  /*  =========== @@ -1453,6 +1483,34 @@ char *ClientConnect( int clientNum, qboolean firstTime )        strcmp( g_password.string, value ) != 0 )      return "Invalid password"; +  schachtmeisterJudgement_t *smj = NULL; + +  if (!(G_admin_permission_guid(guid, ADMF_NOAUTOBAHN) +     || G_admin_permission_guid(guid, ADMF_IMMUNITY))) +  { +    extern g_admin_namelog_t *g_admin_namelog[128]; +    for (i = 0; i < MAX_ADMIN_NAMELOGS && g_admin_namelog[i]; ++i) +    { +      if (!Q_stricmp(g_admin_namelog[i]->ip, ip) +       || !Q_stricmp(g_admin_namelog[i]->guid, guid)) +      { +        schachtmeisterJudgement_t *j = &g_admin_namelog[i]->smj; +        if (j->ratingTime) +        { +          if (j->rating >= g_schachtmeisterClearThreshold.integer) +            break; +          else if (j->rating <= g_schachtmeisterAutobahnThreshold.integer) +          { +            G_LogAutobahn( ent, userinfo, j->rating, qtrue ); +            return g_schachtmeisterAutobahnMessage.string; +          } +          smj = j; +        } +        break; +      } +    } +  } +    // they can connect    ent->client = level.clients + clientNum;    client = ent->client; @@ -1541,7 +1599,6 @@ char *ClientConnect( int clientNum, qboolean firstTime )      CalculateRanks( );      G_admin_namelog_update( client, qfalse );    } -      // if this is after !restart keepteams or !restart switchteams, apply said selection    if ( client->sess.restartTeam != PTE_NONE ) { @@ -1549,6 +1606,27 @@ char *ClientConnect( int clientNum, qboolean firstTime )      client->sess.restartTeam = PTE_NONE;    } +	if( !( G_admin_permission( ent, ADMF_NOAUTOBAHN ) || +	      G_admin_permission( ent, ADMF_IMMUNITY ) ) ) +  { +    extern g_admin_namelog_t *g_admin_namelog[ 128 ]; +    for( i = 0; i < MAX_ADMIN_NAMELOGS && g_admin_namelog[ i ]; i++ ) +    { +      if( !Q_stricmp( ip, g_admin_namelog[ i ]->ip ) || !Q_stricmp( guid, g_admin_namelog[ i ]->guid ) ) +      { +        schachtmeisterJudgement_t *j = &g_admin_namelog[i]->smj; +        if( j->ratingTime ) +        { +          if( j->rating >= g_schachtmeisterClearThreshold.integer ) +            break; +          else if( j->rating <= g_schachtmeisterAutobahnThreshold.integer ) +            return g_schachtmeisterAutobahnMessage.string; +          G_AdminsPrintf( "%s^7 (#%d) has rating %d\n", ent->client->pers.netname, ent - g_entities, j->rating ); +        } +        break; +      } +    } +  }    return NULL;  } diff --git a/src/game/g_cmds.c b/src/game/g_cmds.c index e4f6ad7..c380b45 100644 --- a/src/game/g_cmds.c +++ b/src/game/g_cmds.c @@ -5081,7 +5081,7 @@ static void Cmd_Ignore_f( gentity_t *ent )  commands_t cmds[ ] = {    // normal commands    { "team", 0, Cmd_Team_f }, -  { "vote", CMD_INTERMISSION, Cmd_Vote_f }, +  { "vote", CMD_MESSAGE|CMD_INTERMISSION, Cmd_Vote_f },    { "ignore", 0, Cmd_Ignore_f },    { "unignore", 0, Cmd_Ignore_f }, @@ -5239,6 +5239,14 @@ void ClientCommand( int clientNum )      return;    } +  // Disallow a large class of commands if a player is restricted. +  if( G_admin_is_restricted( ent, qtrue ) && +      ( !Q_stricmp( cmd, "team" ) || +      ( cmds[ i ].cmdFlags & ( CMD_MESSAGE | CMD_TEAM | CMD_NOTEAM ) ) ) ) +  { +    return; +  } +    cmds[ i ].cmdHandler( ent );  } diff --git a/src/game/g_local.h b/src/game/g_local.h index 6aea23d..19b05c9 100644 --- a/src/game/g_local.h +++ b/src/game/g_local.h @@ -1100,6 +1100,7 @@ void      ClientSpawn( gentity_t *ent, gentity_t *spawn, vec3_t origin, vec3_t a  void      player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod );  qboolean  SpotWouldTelefrag( gentity_t *spot );  char     *G_NextNewbieName( gentity_t *ent ); +void      G_LogAutobahn( gentity_t *ent, const char *userinfo, int rating, qboolean onConnect );  //  // g_svcmds.c @@ -1488,6 +1489,10 @@ extern  vmCvar_t  g_Bubbles;  extern  vmCvar_t  g_scrimMode;  extern  vmCvar_t  g_gradualFreeFunds;  extern  vmCvar_t  g_bleedingSpree; +extern  vmCvar_t  g_schachtmeisterClearThreshold; +extern  vmCvar_t  g_schachtmeisterAutobahnThreshold; +extern  vmCvar_t  g_schachtmeisterAutobahnMessage; +extern  vmCvar_t  g_adminAutobahnNotify;  void      trap_Printf( const char *fmt );  void      trap_Error( const char *fmt ); diff --git a/src/game/g_main.c b/src/game/g_main.c index b30f8c0..6623959 100644 --- a/src/game/g_main.c +++ b/src/game/g_main.c @@ -239,6 +239,10 @@ vmCvar_t  g_Bubbles;  vmCvar_t  g_scrimMode;  vmCvar_t  g_gradualFreeFunds;  vmCvar_t  g_bleedingSpree; +vmCvar_t  g_schachtmeisterClearThreshold; +vmCvar_t  g_schachtmeisterAutobahnThreshold; +vmCvar_t  g_schachtmeisterAutobahnMessage; +vmCvar_t  g_adminAutobahnNotify;  static cvarTable_t   gameCvarTable[ ] =  { @@ -455,7 +459,12 @@ static cvarTable_t   gameCvarTable[ ] =    { &g_Bubbles, "g_Bubbles", "1", CVAR_ARCHIVE, 0, qfalse  },    { &g_scrimMode, "g_scrimMode", "0", CVAR_ARCHIVE, 0, qfalse },    { &g_gradualFreeFunds, "g_gradualFreeFunds", "2", CVAR_ARCHIVE, 0, qtrue  }, -  { &g_bleedingSpree, "g_bleedingSpree", "0", CVAR_ARCHIVE, 0, qfalse  } +  { &g_bleedingSpree, "g_bleedingSpree", "0", CVAR_ARCHIVE, 0, qfalse  }, +  { &g_gradualFreeFunds, "g_gradualFreeFunds", "2", CVAR_ARCHIVE, 0, qtrue  }, +  { &g_schachtmeisterClearThreshold, "g_schachtmeisterClearThreshold", "-10", CVAR_ARCHIVE, 0, qfalse }, +  { &g_schachtmeisterAutobahnThreshold, "g_schachtmeisterAutobahnThreshold", "-30", CVAR_ARCHIVE, 0, qfalse }, +  { &g_schachtmeisterAutobahnMessage, "g_schachtmeisterAutobahnMessage", "Your host is blacklisted.", CVAR_ARCHIVE, 0, qfalse }, +  { &g_adminAutobahnNotify, "g_adminAutobahnNotify", "1", CVAR_ARCHIVE, 0, qfalse }  };  static int gameCvarTableSize = sizeof( gameCvarTable ) / sizeof( gameCvarTable[ 0 ] ); @@ -3005,6 +3014,8 @@ void G_RunFrame( int levelTime )    CheckTeamVote( PTE_HUMANS );    CheckTeamVote( PTE_ALIENS ); +  G_admin_schachtmeisterFrame(); +    // for tracking changes    CheckCvars( ); diff --git a/src/game/g_svcmds.c b/src/game/g_svcmds.c index 62148c8..f0d45b1 100644 --- a/src/game/g_svcmds.c +++ b/src/game/g_svcmds.c @@ -703,7 +703,35 @@ qboolean  ConsoleCommand( void )      G_admin_maplog_result( "d" );      return qtrue;    } -   + +  if( !Q_stricmp( cmd, "smr" ) ) +  { +    if( trap_Argc() >= 2 ) +    { +      char arg[ 32 ]; +      trap_Argv( 1, arg, sizeof( arg ) ); + +      if( !Q_stricmp( arg, "ipa" ) && trap_Argc() >= 4 ) +      { +        int rating; +        const char *comment = NULL; + +        trap_Argv( 3, arg, sizeof( arg ) ); +        rating = atoi( arg ); +        if( trap_Argc() >= 5 ) +          comment = ConcatArgs( 4 ); +        trap_Argv( 2, arg, sizeof( arg ) ); + +        G_admin_IPA_judgement( arg, rating, comment ); + +        return qtrue; +      } +    } + +    G_Printf( "unrecognized Schachtmeister response: %s\n", ConcatArgs( 1 ) ); +    return qtrue; +  } +    // see if this is a a admin command    if( G_admin_cmd_check( NULL, qfalse ) )      return qtrue;  | 
