diff options
-rw-r--r-- | src/game/g_admin.c | 242 | ||||
-rw-r--r-- | src/game/g_admin.h | 62 |
2 files changed, 132 insertions, 172 deletions
diff --git a/src/game/g_admin.c b/src/game/g_admin.c index 8d8c18b4..2650d6ff 100644 --- a/src/game/g_admin.c +++ b/src/game/g_admin.c @@ -38,7 +38,7 @@ static char g_bfb[ 32000 ]; // note: list ordered alphabetically g_admin_cmd_t g_admin_cmds[ ] = { - {"adjustban", G_admin_adjustban, "b", + {"adjustban", G_admin_adjustban, "ban", "change the duration or reason of a ban. duration is specified as " "numbers followed by units 'w' (weeks), 'd' (days), 'h' (hours) or " "'m' (minutes), or seconds if no units are specified. if the duration is" @@ -47,22 +47,22 @@ g_admin_cmd_t g_admin_cmds[ ] = "[^3ban#^7] (^5duration^7) (^5reason^7)" }, - {"admintest", G_admin_admintest, "a", + {"admintest", G_admin_admintest, "admintest", "display your current admin level", "" }, - {"allowbuild", G_admin_denybuild, "d", + {"allowbuild", G_admin_denybuild, "denybuild", "restore a player's ability to build", "[^3name|slot#^7]" }, - {"allready", G_admin_allready, "y", + {"allready", G_admin_allready, "allready", "makes everyone ready in intermission", "" }, - {"ban", G_admin_ban, "b", + {"ban", G_admin_ban, "ban", "ban a player by IP and GUID with an optional expiration time and reason." " duration is specified as numbers followed by units 'w' (weeks), 'd' " "(days), 'h' (hours) or 'm' (minutes), or seconds if no units are " @@ -70,120 +70,120 @@ g_admin_cmd_t g_admin_cmds[ ] = "[^3name|slot#|IP^7] (^5duration^7) (^5reason^7)" }, - {"cancelvote", G_admin_endvote, "c", + {"cancelvote", G_admin_endvote, "cancelvote", "cancel a vote taking place", "(^5a|h^7)" }, - {"denybuild", G_admin_denybuild, "d", + {"denybuild", G_admin_denybuild, "denybuild", "take away a player's ability to build", "[^3name|slot#^7]" }, - {"help", G_admin_help, "h", + {"help", G_admin_help, "help", "display commands available to you or help on a specific command", "(^5command^7)" }, - {"kick", G_admin_kick, "k", + {"kick", G_admin_kick, "kick", "kick a player with an optional reason", "[^3name|slot#^7] (^5reason^7)" }, - {"listadmins", G_admin_listadmins, "D", + {"listadmins", G_admin_listadmins, "listadmins", "display a list of all server admins and their levels", "(^5name|start admin#^7)" }, - {"listlayouts", G_admin_listlayouts, "L", + {"listlayouts", G_admin_listlayouts, "listlayouts", "display a list of all available layouts for a map", "(^5mapname^7)" }, - {"listplayers", G_admin_listplayers, "i", + {"listplayers", G_admin_listplayers, "listplayers", "display a list of players, their client numbers and their levels", "" }, - {"lock", G_admin_lock, "K", + {"lock", G_admin_lock, "lock", "lock a team to prevent anyone from joining it", "[^3a|h^7]" }, - {"map", G_admin_map, "M", + {"map", G_admin_map, "map", "load a map (and optionally force layout)", "[^3mapname^7] (^5layout^7)" }, - {"mute", G_admin_mute, "m", + {"mute", G_admin_mute, "mute", "mute a player", "[^3name|slot#^7]" }, - {"namelog", G_admin_namelog, "e", + {"namelog", G_admin_namelog, "namelog", "display a list of names used by recently connected players", "(^5name^7)" }, - {"nextmap", G_admin_nextmap, "n", + {"nextmap", G_admin_nextmap, "nextmap", "go to the next map in the cycle", "" }, - {"passvote", G_admin_endvote, "V", + {"passvote", G_admin_endvote, "passvote", "pass a vote currently taking place", "(^5a|h^7)" }, - {"putteam", G_admin_putteam, "p", + {"putteam", G_admin_putteam, "putteam", "move a player to a specified team", "[^3name|slot#^7] [^3h|a|s^7]" }, - {"readconfig", G_admin_readconfig, "G", + {"readconfig", G_admin_readconfig, "readconfig", "reloads the admin config file and refreshes permission flags", "" }, - {"rename", G_admin_rename, "N", + {"rename", G_admin_rename, "rename", "rename a player", "[^3name|slot#^7] [^3new name^7]" }, - {"restart", G_admin_restart, "r", + {"restart", G_admin_restart, "restart", "restart the current map (optionally using named layout)", "(^5layout^7)" }, - {"setlevel", G_admin_setlevel, "s", + {"setlevel", G_admin_setlevel, "setlevel", "sets the admin level of a player", "[^3name|slot#|admin#^7] [^3level^7]" }, - {"showbans", G_admin_showbans, "B", + {"showbans", G_admin_showbans, "showbans", "display a (partial) list of active bans", "(^5start at ban#^7) (^5name|IP^7)" }, - {"spec999", G_admin_spec999, "P", + {"spec999", G_admin_spec999, "spec999", "move 999 pingers to the spectator team", ""}, - {"time", G_admin_time, "C", + {"time", G_admin_time, "time", "show the current local server time", ""}, - {"unban", G_admin_unban, "b", + {"unban", G_admin_unban, "ban", "unbans a player specified by the slot as seen in showbans", "[^3ban#^7]" }, - {"unlock", G_admin_lock, "K", + {"unlock", G_admin_lock, "lock", "unlock a locked team", "[^3a|h^7]" }, - {"unmute", G_admin_mute, "m", + {"unmute", G_admin_mute, "mute", "unmute a muted player", "[^3name|slot#^7]" } @@ -198,11 +198,41 @@ g_admin_ban_t *g_admin_bans[ MAX_ADMIN_BANS ]; g_admin_command_t *g_admin_commands[ MAX_ADMIN_COMMANDS ]; g_admin_namelog_t *g_admin_namelog[ MAX_ADMIN_NAMELOGS ]; -qboolean G_admin_permission( gentity_t *ent, char flag ) +// match a certain flag within these flags +static qboolean admin_permission( char *flags, const char *flag, qboolean *perm ) +{ + char *token, *token_p = flags; + while( *( token = COM_Parse( &token_p ) ) ) + { + *perm = qtrue; + if( *token == '-' || *token == '+' ) + *perm = *token++ == '+'; + if( !strcmp( token, flag ) ) + return qtrue; + if( !strcmp( token, ADMF_ALLFLAGS ) ) + { + while( *( token = COM_Parse( &token_p ) ) ) + { + // -ALLFLAGS +flag or ALLFLAGS -flag + if( *token != ( *perm ? '-' : '+' ) ) + continue; + if( !strcmp( token + 1, flag ) ) + { + *perm = !*perm; + break; + } + } + return qtrue; + } + } + return qfalse; +} + +qboolean G_admin_permission( gentity_t *ent, const char *flag ) { int i; int l = 0; - char *flags; + qboolean perm = qfalse; // console always wins if( !ent ) @@ -212,62 +242,17 @@ qboolean G_admin_permission( gentity_t *ent, char flag ) { if( !Q_stricmp( ent->client->pers.guid, g_admin_admins[ i ]->guid ) ) { - flags = g_admin_admins[ i ]->flags; - while( *flags ) - { - if( *flags == flag ) - return qtrue; - else if( *flags == '-' ) - { - while( *flags++ ) - { - if( *flags == flag ) - return qfalse; - if( *flags == '+' ) - break; - } - } - else if( *flags == '*' ) - { - while( *flags++ ) - { - if( *flags == flag ) - return qfalse; - } - // flags with significance only for individuals ( - // like ADMF_INCOGNITO and ADMF_IMMUTABLE are NOT covered - // by the '*' wildcard. They must be specified manually. - return ( flag != ADMF_INCOGNITO && flag != ADMF_IMMUTABLE ); - } - flags++; - } + if( admin_permission( g_admin_admins[ i ]->flags, flag, &perm ) ) + return perm; l = g_admin_admins[ i ]->level; + break; } } for( i = 0; i < MAX_ADMIN_LEVELS && g_admin_levels[ i ]; i++ ) { if( g_admin_levels[ i ]->level == l ) - { - flags = g_admin_levels[ i ]->flags; - while( *flags ) - { - if( *flags == flag ) - return qtrue; - if( *flags == '*' ) - { - while( *flags++ ) - { - if( *flags == flag ) - return qfalse; - } - // flags with significance only for individuals ( - // like ADMF_INCOGNITO and ADMF_IMMUTABLE are NOT covered - // by the '*' wildcard. They must be specified manually. - return ( flag != ADMF_INCOGNITO && flag != ADMF_IMMUTABLE ); - } - flags++; - } - } + return admin_permission( g_admin_levels[ i ]->flags, flag, &perm ) && + perm; } return qfalse; } @@ -325,6 +310,7 @@ static qboolean admin_higher_guid( char *admin_guid, char *victim_guid ) { int i; int alevel = 0; + qboolean perm = qfalse; for( i = 0; i < MAX_ADMIN_ADMINS && g_admin_admins[ i ]; i++ ) { @@ -340,7 +326,8 @@ static qboolean admin_higher_guid( char *admin_guid, char *victim_guid ) { if( alevel < g_admin_admins[ i ]->level ) return qfalse; - return !strstr( g_admin_admins[ i ]->flags, va( "%c", ADMF_IMMUTABLE ) ); + return !admin_permission( g_admin_admins[ i ]->flags, ADMF_IMMUNITY, + &perm ) || !perm; } } return qtrue; @@ -457,13 +444,8 @@ static void admin_writeconfig( void ) admin_writeconfig_string( g_admin_commands[ i ]->exec, f ); trap_FS_Write( "desc = ", 10, f ); admin_writeconfig_string( g_admin_commands[ i ]->desc, f ); - trap_FS_Write( "levels = ", 10, f ); - for( j = 0; g_admin_commands[ i ]->levels[ j ] != -1; j++ ) - { - Q_strcat( levels, sizeof( levels ), - va( "%i ", g_admin_commands[ i ]->levels[ j ] ) ); - } - admin_writeconfig_string( levels, f ); + trap_FS_Write( "flag = ", 10, f ); + admin_writeconfig_string( g_admin_commands[ i ]->flag, f ); trap_FS_Write( "\n", 1, f ); } trap_FS_FCloseFile( f ); @@ -531,27 +513,40 @@ static void admin_default_levels( void ) } Q_strncpyz( g_admin_levels[ 0 ]->name, "^4Unknown Player", sizeof( l->name ) ); - Q_strncpyz( g_admin_levels[ 0 ]->flags, "iahC", sizeof( l->flags ) ); + Q_strncpyz( g_admin_levels[ 0 ]->flags, + "listplayers admintest help time", + sizeof( l->flags ) ); Q_strncpyz( g_admin_levels[ 1 ]->name, "^5Server Regular", sizeof( l->name ) ); - Q_strncpyz( g_admin_levels[ 1 ]->flags, "iahC", sizeof( l->flags ) ); + Q_strncpyz( g_admin_levels[ 1 ]->flags, + "listplayers admintest help time", + sizeof( l->flags ) ); Q_strncpyz( g_admin_levels[ 2 ]->name, "^6Team Manager", sizeof( l->name ) ); - Q_strncpyz( g_admin_levels[ 2 ]->flags, "iahCpP", sizeof( l->flags ) ); + Q_strncpyz( g_admin_levels[ 2 ]->flags, + "listplayers admintest help time putteam spec999", + sizeof( l->flags ) ); Q_strncpyz( g_admin_levels[ 3 ]->name, "^2Junior Admin", sizeof( l->name ) ); - Q_strncpyz( g_admin_levels[ 3 ]->flags, "iahCpPkm?", sizeof( l->flags ) ); + Q_strncpyz( g_admin_levels[ 3 ]->flags, + "listplayers admintest help time putteam spec999 kick mute ADMINCHAT", + sizeof( l->flags ) ); Q_strncpyz( g_admin_levels[ 4 ]->name, "^3Senior Admin", sizeof( l->name ) ); - Q_strncpyz( g_admin_levels[ 4 ]->flags, "iahCpPkmBbe?", sizeof( l->flags ) ); + Q_strncpyz( g_admin_levels[ 4 ]->flags, + "listplayers admintest help time putteam spec99 kick mute showbans ban " + "namelog ADMINCHAT", + sizeof( l->flags ) ); Q_strncpyz( g_admin_levels[ 5 ]->name, "^1Server Operator", sizeof( l->name ) ); - Q_strncpyz( g_admin_levels[ 5 ]->flags, "*", sizeof( l->flags ) ); + Q_strncpyz( g_admin_levels[ 5 ]->flags, + "ALLFLAGS -IMMUTABLE -INCOGNITO", + sizeof( l->flags ) ); admin_level_maxname = 15; } @@ -574,30 +569,6 @@ int G_admin_level( gentity_t *ent ) return 0; } -static qboolean admin_command_permission( gentity_t *ent, char *command ) -{ - int i, j; - int level; - - if( !ent ) - return qtrue; - level = ent->client->pers.adminLevel; - for( i = 0; i < MAX_ADMIN_COMMANDS && g_admin_commands[ i ]; i++ ) - { - if( !Q_stricmp( command, g_admin_commands[ i ]->command ) ) - { - for( j = 0; g_admin_commands[ i ]->levels[ j ] != -1; j++ ) - { - if( g_admin_commands[ i ]->levels[ j ] == level ) - { - return qtrue; - } - } - } - } - return qfalse; -} - static void admin_log( gentity_t *admin, char *cmd, int skiparg ) { fileHandle_t f; @@ -900,7 +871,7 @@ qboolean G_admin_cmd_check( gentity_t *ent, qboolean say ) if( Q_stricmp( cmd, g_admin_commands[ i ]->command ) ) continue; - if( admin_command_permission( ent, cmd ) ) + if( G_admin_permission( ent, g_admin_commands[ i ]->flag ) ) { // flooding say will have already been accounted for in ClientCommand if( !say && G_FloodLimited( ent ) ) @@ -921,7 +892,7 @@ qboolean G_admin_cmd_check( gentity_t *ent, qboolean say ) if( Q_stricmp( cmd, g_admin_cmds[ i ].keyword ) ) continue; - if( G_admin_permission( ent, g_admin_cmds[ i ].flag[ 0 ] ) ) + if( G_admin_permission( ent, g_admin_cmds[ i ].flag ) ) { // flooding say will have already been accounted for in ClientCommand if( !say && G_FloodLimited( ent ) ) @@ -1091,7 +1062,6 @@ qboolean G_admin_readconfig( gentity_t *ent, int skiparg ) return qfalse; c = BG_Alloc( sizeof( g_admin_command_t ) ); g_admin_commands[ cc++ ] = c; - c->levels[ 0 ] = -1; command_open = qtrue; level_open = admin_open = ban_open = qfalse; } @@ -1191,23 +1161,9 @@ qboolean G_admin_readconfig( gentity_t *ent, int skiparg ) { admin_readconfig_string( &cnf, c->desc, sizeof( c->desc ) ); } - else if( !Q_stricmp( t, "levels" ) ) + else if( !Q_stricmp( t, "flag" ) ) { - char levels[ MAX_STRING_CHARS ] = {""}; - char *level = levels; - char *lp; - int cmdlevel = 0; - - admin_readconfig_string( &cnf, levels, sizeof( levels ) ); - while( cmdlevel < MAX_ADMIN_LEVELS ) - { - lp = COM_Parse( &level ); - if( !*lp ) - break; - c->levels[ cmdlevel++ ] = atoi( lp ); - } - // ensure the list is -1 terminated - c->levels[ cmdlevel ] = -1; + admin_readconfig_string( &cnf, c->flag, sizeof( c->flag ) ); } else { @@ -2480,7 +2436,7 @@ qboolean G_admin_help( gentity_t *ent, int skiparg ) ADMBP_begin(); for( i = 0; i < adminNumCmds; i++ ) { - if( G_admin_permission( ent, g_admin_cmds[ i ].flag[ 0 ] ) ) + if( G_admin_permission( ent, g_admin_cmds[ i ].flag ) ) { ADMBP( va( "^3!%-12s", g_admin_cmds[ i ].keyword ) ); count++; @@ -2491,7 +2447,7 @@ qboolean G_admin_help( gentity_t *ent, int skiparg ) } for( i = 0; i < MAX_ADMIN_COMMANDS && g_admin_commands[ i ]; i++ ) { - if( ! admin_command_permission( ent, g_admin_commands[ i ]->command ) ) + if( !G_admin_permission( ent, g_admin_commands[ i ]->flag ) ) continue; ADMBP( va( "^3!%-12s", g_admin_commands[ i ]->command ) ); count++; @@ -2520,7 +2476,7 @@ qboolean G_admin_help( gentity_t *ent, int skiparg ) { if( !Q_stricmp( cmd, g_admin_cmds[ i ].keyword ) ) { - if( !G_admin_permission( ent, g_admin_cmds[ i ].flag[ 0 ] ) ) + if( !G_admin_permission( ent, g_admin_cmds[ i ].flag ) ) { ADMBP( va( "^3!help: ^7you do not have permission to use '%s'\n", g_admin_cmds[ i ].keyword ) ); @@ -2532,7 +2488,7 @@ qboolean G_admin_help( gentity_t *ent, int skiparg ) ADMBP( va( " ^3Function: ^7%s\n", g_admin_cmds[ i ].function ) ); ADMBP( va( " ^3Syntax: ^7!%s %s\n", g_admin_cmds[ i ].keyword, g_admin_cmds[ i ].syntax ) ); - ADMBP( va( " ^3Flag: ^7'%c'\n", g_admin_cmds[ i ].flag[ 0 ] ) ); + ADMBP( va( " ^3Flag: ^7'%s'\n", g_admin_cmds[ i ].flag ) ); ADMBP_end(); return qtrue; } @@ -2541,7 +2497,7 @@ qboolean G_admin_help( gentity_t *ent, int skiparg ) { if( !Q_stricmp( cmd, g_admin_commands[ i ]->command ) ) { - if( !admin_command_permission( ent, g_admin_commands[ i ]->command ) ) + if( !G_admin_permission( ent, g_admin_commands[ i ]->flag ) ) { ADMBP( va( "^3!help: ^7you do not have permission to use '%s'\n", g_admin_commands[ i ]->command ) ); diff --git a/src/game/g_admin.h b/src/game/g_admin.h index 7dbe6d02..bdf44e4b 100644 --- a/src/game/g_admin.h +++ b/src/game/g_admin.h @@ -36,40 +36,44 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define MAX_ADMIN_BANS 1024 #define MAX_ADMIN_NAMELOGS 128 #define MAX_ADMIN_NAMELOG_NAMES 5 -#define MAX_ADMIN_FLAGS 64 +#define MAX_ADMIN_FLAG_LEN 20 +#define MAX_ADMIN_FLAGS 1024 #define MAX_ADMIN_COMMANDS 64 #define MAX_ADMIN_CMD_LEN 20 #define MAX_ADMIN_BAN_REASON 50 /* - * 1 - cannot be vote kicked, vote muted - * 2 - cannot be censored or flood protected TODO - * 4 - can see team chat as a spectator - * 5 - can switch teams any time, regardless of balance - * 6 - does not need to specify a reason for a kick/ban - * 7 - can call a vote at any time (regardless of a vote being disabled or - * voting limitations) - * 8 - does not need to specify a duration for a ban - * 9 - can run commands from team chat - * 0 - inactivity rules do not apply to them - * ! - admin commands cannot be used on them - * @ - does not show up as an admin in !listplayers - * $ - sees all information in !listplayers + * IMMUNITY - cannot be vote kicked, vote muted + * NOCENSORFLOOD - cannot be censored or flood protected + * TEAMCHANGEFREE - never loses credits for changing teams + * SPECALLCHAT - can see team chat as a spectator + * FORCETEAMCHANGE - can switch teams any time, regardless of balance + * UNACCOUNTABLE - does not need to specify a reason for a kick/ban + * NOVOTELIMIT - can call a vote at any time (regardless of a vote being + * disabled or voting limitations) + * CANPERMBAN - does not need to specify a duration for a ban + * TEAMCHATCMD - can run commands from team chat + * ACTIVITY - inactivity rules do not apply to them + * IMMUTABLE - admin commands cannot be used on them + * INCOGNITO - does not show up as an admin in !listplayers + * ALLFLAGS - all flags (including command flags) apply to this player * ? - receieves and can send /a admin messages */ -#define ADMF_IMMUNITY '1' -#define ADMF_NOCENSORFLOOD '2' /* TODO */ -#define ADMF_SPEC_ALLCHAT '4' -#define ADMF_FORCETEAMCHANGE '5' -#define ADMF_UNACCOUNTABLE '6' -#define ADMF_NO_VOTE_LIMIT '7' -#define ADMF_CAN_PERM_BAN '8' -#define ADMF_TEAMCHAT_CMD '9' -#define ADMF_ACTIVITY '0' - -#define ADMF_IMMUTABLE '!' -#define ADMF_INCOGNITO '@' -#define ADMF_ADMINCHAT '?' +#define ADMF_IMMUNITY "IMMUNITY" +#define ADMF_NOCENSORFLOOD "NOCENSORFLOOD" +#define ADMF_TEAMCHANGEFREE "TEAMCHANGEFREE" +#define ADMF_SPEC_ALLCHAT "SPECALLCHAT" +#define ADMF_FORCETEAMCHANGE "FORCETEAMCHANGE" +#define ADMF_UNACCOUNTABLE "UNACCOUNTABLE" +#define ADMF_NO_VOTE_LIMIT "NOVOTELIMIT" +#define ADMF_CAN_PERM_BAN "CANPERMBAN" +#define ADMF_TEAMCHAT_CMD "TEAMCHATCMD" +#define ADMF_ACTIVITY "ACTIVITY" + +#define ADMF_IMMUTABLE "IMMUTABLE" +#define ADMF_INCOGNITO "INCOGNITO" +#define ADMF_ALLFLAGS "ALLFLAGS" +#define ADMF_ADMINCHAT "ADMINCHAT" #define MAX_ADMIN_LISTITEMS 20 #define MAX_ADMIN_SHOWBANS 10 @@ -120,7 +124,7 @@ typedef struct g_admin_command char command[ MAX_ADMIN_CMD_LEN ]; char exec[ MAX_QPATH ]; char desc[ 50 ]; - int levels[ MAX_ADMIN_LEVELS + 1 ]; + char flag[ MAX_ADMIN_FLAG_LEN ]; } g_admin_command_t; @@ -137,7 +141,7 @@ g_admin_namelog_t; qboolean G_admin_ban_check( char *userinfo, char *reason, int rlen ); qboolean G_admin_cmd_check( gentity_t *ent, qboolean say ); qboolean G_admin_readconfig( gentity_t *ent, int skiparg ); -qboolean G_admin_permission( gentity_t *ent, char flag ); +qboolean G_admin_permission( gentity_t *ent, const char *flag ); qboolean G_admin_name_check( gentity_t *ent, char *name, char *err, int len ); void G_admin_namelog_update( gclient_t *ent, qboolean disconnect ); int G_admin_level( gentity_t *ent ); |