plugins/basecommands.sp
author David Anderson <dvander@alliedmods.net>
Fri Jun 15 20:23:40 2007 +0000 (2007-06-15)
changeset 938 8e95112b2501
parent 937 b2626cdace51
child 981 2a71d877c501
permissions -rw-r--r--
added a hacky way to get NULL references
     1 /**
     2  * basecommands.sp
     3  * Implements basic admin commands.
     4  * This file is part of SourceMod, Copyright (C) 2004-2007 AlliedModders LLC
     5  *
     6  * This program is free software; you can redistribute it and/or
     7  * modify it under the terms of the GNU General Public License
     8  * as published by the Free Software Foundation; either version 2
     9  * of the License, or (at your option) any later version.
    10  *
    11  * This program is distributed in the hope that it will be useful,
    12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    14  * GNU General Public License for more details.
    15  * 
    16  * You should have received a copy of the GNU General Public License
    17  * along with this program; if not, write to the Free Software
    18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
    19  *
    20  * Version: $Id$
    21  */
    22 
    23 #include <sourcemod>
    24 
    25 #pragma semicolon 1
    26 
    27 public Plugin:myinfo = 
    28 {
    29 	name = "Basic Commands",
    30 	author = "AlliedModders LLC",
    31 	description = "Basic Admin Commands",
    32 	version = SOURCEMOD_VERSION,
    33 	url = "http://www.sourcemod.net/"
    34 };
    35 
    36 new Handle:hBanForward = INVALID_HANDLE;
    37 new Handle:hAddBanForward = INVALID_HANDLE;
    38 new Handle:hBanRemoved = INVALID_HANDLE;
    39 
    40 public OnPluginStart()
    41 {
    42 	LoadTranslations("common.cfg");
    43 	LoadTranslations("plugin.basecommands.cfg");
    44 	RegAdminCmd("sm_kick", Command_Kick, ADMFLAG_KICK, "sm_kick <#userid|name> [reason]");
    45 	RegAdminCmd("sm_map", Command_Map, ADMFLAG_CHANGEMAP, "sm_map <map>");
    46 	RegAdminCmd("sm_rcon", Command_Rcon, ADMFLAG_RCON, "sm_rcon <args>");
    47 	RegAdminCmd("sm_cvar", Command_Cvar, ADMFLAG_CONVARS, "sm_cvar <cvar> [value]");
    48 	RegAdminCmd("sm_execcfg", Command_ExecCfg, ADMFLAG_CONFIG, "sm_execcfg <filename>");
    49 	RegAdminCmd("sm_who", Command_Who, ADMFLAG_GENERIC, "sm_who [#userid|name]");
    50 	RegAdminCmd("sm_ban", Command_Ban, ADMFLAG_BAN, "sm_ban <#userid|name> <minutes|0> [reason]");
    51 	RegAdminCmd("sm_unban", Command_Unban, ADMFLAG_UNBAN, "sm_unban <steamid>");
    52 	RegAdminCmd("sm_addban", Command_AddBan, ADMFLAG_RCON, "sm_addban <time> <steamid> [reason]");
    53 	RegAdminCmd("sm_banip", Command_BanIp, ADMFLAG_RCON, "sm_banip <time> <ip> [reason]");
    54 	
    55 	hBanForward = CreateGlobalForward("OnClientBanned", ET_Ignore, Param_Cell, Param_Cell, Param_Cell, Param_String);
    56 	hAddBanForward = CreateGlobalForward("OnBanAdded", ET_Ignore, Param_Cell, Param_String, Param_Cell, Param_String);
    57 	hBanRemoved = CreateGlobalForward("OnBanRemoved", ET_Ignore, Param_Cell, Param_String);
    58 }
    59 
    60 public Action:Command_BanIp(client, args)
    61 {
    62 	if (args < 2)
    63 	{
    64 		ReplyToCommand(client, "[SM] Usage: sm_banip <time> <ip> [reason]");
    65 		return Plugin_Handled;
    66 	}
    67 	
    68 	new String:arg[50], String:time[20];
    69 	GetCmdArg(1, time, sizeof(time));
    70 	GetCmdArg(2, arg, sizeof(arg));
    71 	
    72 	new minutes = StringToInt(time);
    73 	
    74 	new String:reason[128];
    75 	if (args >= 3)
    76 	{
    77 		GetCmdArg(3, reason, sizeof(reason));
    78 	}
    79 	
    80 	LogMessage("\"%L\" added ban (minutes \"%d\") (ip \"%s\") (reason \"%s\")", client, minutes, arg, reason);
    81 	
    82 	Call_StartForward(hAddBanForward);
    83 	Call_PushCell(client);
    84 	Call_PushString(arg);
    85 	Call_PushCell(minutes);
    86 	Call_PushString(reason);
    87 	Call_Finish();
    88 	
    89 	ServerCommand("banip %d %s", minutes, arg);
    90 	ServerCommand("writeip");
    91 	ReplyToCommand(client, "[SM] %t", "Ban added");
    92 	
    93 	return Plugin_Handled;
    94 }
    95 
    96 public Action:Command_AddBan(client, args)
    97 {
    98 	if (args < 2)
    99 	{
   100 		ReplyToCommand(client, "[SM] Usage: sm_addban <time> <steamid> [reason]");
   101 		return Plugin_Handled;
   102 	}
   103 	
   104 	new String:arg[50], String:time[20];
   105 	GetCmdArg(1, time, sizeof(time));
   106 	GetCmdArg(2, arg, sizeof(arg));
   107 	
   108 	new minutes = StringToInt(time);
   109 	
   110 	new String:reason[128];
   111 	if (args >= 3)
   112 	{
   113 		GetCmdArg(3, reason, sizeof(reason));
   114 	}
   115 	
   116 	LogMessage("\"%L\" added ban (minutes \"%d\") (id \"%s\") (reason \"%s\")", client, minutes, arg, reason);
   117 	
   118 	Call_StartForward(hAddBanForward);
   119 	Call_PushCell(client);
   120 	Call_PushString(arg);
   121 	Call_PushCell(minutes);
   122 	Call_PushString(reason);
   123 	Call_Finish();
   124 	
   125 	ServerCommand("banid %d %s", minutes, arg);
   126 	ServerCommand("writeid");
   127 	ReplyToCommand(client, "[SM] %t", "Ban added");
   128 	
   129 	return Plugin_Handled;
   130 }
   131 
   132 public Action:Command_Unban(client, args)
   133 {
   134 	if (args < 1)
   135 	{
   136 		ReplyToCommand(client, "[SM] Usage: sm_unban <steamid>");
   137 		return Plugin_Handled;
   138 	}
   139 	
   140 	new String:arg[50], start=0;
   141 	new String:new_arg[50];
   142 	GetCmdArgString(arg, sizeof(arg));
   143 	
   144 	if (strncmp(arg, "STEAM_0:", 8) == 0)
   145 	{
   146 		start = 8;
   147 	} else if (strncmp(arg, "0:1:", 4) == 0 || strncmp(arg, "0:0:", 4) == 0)
   148 	{
   149 		start = 2;
   150 	}
   151 	
   152 	LogMessage("\"%L\" removed ban (filter \"%s\")", arg[start]);
   153 	
   154 	Format(new_arg, sizeof(new_arg), "STEAM_0:%s", arg[start]);
   155 	Call_StartForward(hBanRemoved);
   156 	Call_PushCell(client);
   157 	Call_PushString(new_arg);
   158 	Call_Finish();
   159 	
   160 	ServerCommand("removeid \"%s\"", arg[start]);
   161 	ServerCommand("writeid");
   162 	ReplyToCommand(client, "[SM] %t", "Removed bans matching", arg);
   163 	
   164 	return Plugin_Handled;
   165 }
   166 
   167 public Action:Command_Ban(client, args)
   168 {
   169 	if (args < 2)
   170 	{
   171 		ReplyToCommand(client, "[SM] Usage: sm_ban <#userid|name> <minutes|0> [reason]");
   172 		return Plugin_Handled;
   173 	}
   174 	
   175 	new String:arg[65];
   176 	GetCmdArg(1, arg, sizeof(arg));
   177 	
   178 	new clients[2];
   179 	new numClients = SearchForClients(arg, clients, 2);
   180 	
   181 	if (numClients == 0)
   182 	{
   183 		ReplyToCommand(client, "[SM] %t", "No matching client");
   184 		return Plugin_Handled;
   185 	} else if (numClients > 1) {
   186 		ReplyToCommand(client, "[SM] %t", "More than one client matches", arg);
   187 		return Plugin_Handled;
   188 	} else if (!CanUserTarget(client, clients[0])) {
   189 		ReplyToCommand(client, "[SM] %t", "Unable to target");
   190 		return Plugin_Handled;
   191 	} else if (IsFakeClient(clients[0])) {
   192 		ReplyToCommand(client, "[SM] %t", "Cannot target bot");
   193 		return Plugin_Handled;
   194 	}
   195 	
   196 	new String:s_time[12];
   197 	GetCmdArg(2, s_time, sizeof(s_time));
   198 	
   199 	new time = StringToInt(s_time);
   200 	
   201 	decl String:reason[128];
   202 	if (args >= 3)
   203 	{
   204 		GetCmdArg(3, reason, sizeof(reason));
   205 	} else {
   206 		reason[0] = '\0';
   207 	}
   208 	
   209 	new userid = GetClientUserId(clients[0]);
   210 	GetClientName(clients[0], arg, sizeof(arg));
   211 	
   212 	if (time)
   213 	{
   214 		if (reason[0] == '\0')
   215 		{
   216 			ShowActivity(client, "%t", "Permabanned player", arg);
   217 		} else {
   218 			ShowActivity(client, "%t", "Permabanned player reason", arg, reason);
   219 		}
   220 	} else {
   221 		if (reason[0] == '\0')
   222 		{
   223 			ShowActivity(client, "%t", "Banned player", arg, time);
   224 		} else {
   225 			ShowActivity(client, "%t", "Banned player reason", arg, time, reason);
   226 		}
   227 	}
   228 	
   229 	LogMessage("\"%L\" banned \"%L\" (minutes \"%d\") (reason \"%s\")", client, clients[0], time, reason);
   230 	
   231 	/* Fire the ban forward */
   232 	Call_StartForward(hBanForward);
   233 	Call_PushCell(client);
   234 	Call_PushCell(clients[0]);
   235 	Call_PushCell(time);
   236 	Call_PushString(reason);
   237 	Call_Finish();
   238 
   239 	if (reason[0] == '\0')
   240 	{
   241 		strcopy(reason, sizeof(reason), "Banned");
   242 	}
   243 	
   244 	ServerCommand("banid %d %d", time, userid);
   245 	ServerCommand("kickid %d \"%s\"", userid, reason);
   246 	
   247 	if (time == 0)
   248 	{
   249 		ServerCommand("writeid");
   250 	}
   251 	
   252 	return Plugin_Handled;
   253 }
   254 
   255 #define FLAG_STRINGS		14
   256 new String:g_FlagNames[FLAG_STRINGS][20] =
   257 {
   258 	"reservation",
   259 	"admin",
   260 	"kick",
   261 	"ban",
   262 	"unban",
   263 	"slay",
   264 	"map",
   265 	"cvars",
   266 	"cfg",
   267 	"chat",
   268 	"vote",
   269 	"pass",
   270 	"rcon",
   271 	"cheat"
   272 };
   273 
   274 FlagsToString(String:buffer[], maxlength, flags)
   275 {
   276 	new String:joins[FLAG_STRINGS][20];
   277 	new total;
   278 	
   279 	for (new i=0; i<FLAG_STRINGS; i++)
   280 	{
   281 		if (flags & (1<<i))
   282 		{
   283 			strcopy(joins[total++], 20, g_FlagNames[i]);
   284 		}
   285 	}
   286 	
   287 	ImplodeStrings(joins, total, ", ", buffer, maxlength);
   288 }
   289 
   290 public Action:Command_Who(client, args)
   291 {
   292 	if (args < 1)
   293 	{
   294 		/* Display header */
   295 		new String:t_access[16], String:t_name[16];
   296 		Format(t_access, sizeof(t_access), "%t", "Access", client);
   297 		Format(t_name, sizeof(t_name), "%t", "Name", client);
   298 		
   299 		PrintToConsole(client, "%-24.23s %s", t_name, t_access);
   300 		
   301 		/* List all players */
   302 		new maxClients = GetMaxClients();
   303 		new String:flagstring[255];
   304 				
   305 		for (new i=1; i<=maxClients; i++)
   306 		{
   307 			if (!IsClientInGame(i))
   308 			{
   309 				continue;
   310 			}
   311 			new flags = GetUserFlagBits(i);
   312 			if (flags == 0)
   313 			{
   314 				strcopy(flagstring, sizeof(flagstring), "none");
   315 			} else if (flags & ADMFLAG_ROOT) {
   316 				strcopy(flagstring, sizeof(flagstring), "root");
   317 			} else {
   318 				FlagsToString(flagstring, sizeof(flagstring), flags);
   319 			}
   320 			decl String:name[65];
   321 			GetClientName(i, name, sizeof(name));
   322 			PrintToConsole(client, "%d. %-24.23s %s", i, name, flagstring);
   323 		}
   324 		
   325 		if (GetCmdReplySource() == SM_REPLY_TO_CHAT)
   326 		{
   327 			ReplyToCommand(client, "[SM] %t", "See console for output");
   328 		}
   329 		
   330 		return Plugin_Handled;
   331 	}
   332 	
   333 	new String:arg[65];
   334 	GetCmdArg(1, arg, sizeof(arg));
   335 	
   336 	new clients[2];
   337 	new numClients = SearchForClients(arg, clients, 2);
   338 	
   339 	if (numClients == 0)
   340 	{
   341 		ReplyToCommand(client, "[SM] %t", "No matching client");
   342 		return Plugin_Handled;
   343 	} else if (numClients > 1) {
   344 		ReplyToCommand(client, "[SM] %t", "More than one client matches", arg);
   345 		return Plugin_Handled;
   346 	}
   347 	
   348 	new flags = GetUserFlagBits(clients[0]);
   349 	new String:flagstring[255];
   350 	if (flags == 0)
   351 	{
   352 		strcopy(flagstring, sizeof(flagstring), "none");
   353 	} else if (flags & ADMFLAG_ROOT) {
   354 		strcopy(flagstring, sizeof(flagstring), "root");
   355 	} else {
   356 		FlagsToString(flagstring, sizeof(flagstring), flags);
   357 	}
   358 	
   359 	ReplyToCommand(client, "[SM] %t: %s", "Access", flagstring);
   360 	
   361 	return Plugin_Handled;
   362 }
   363 
   364 public Action:Command_ExecCfg(client, args)
   365 {
   366 	if (args < 1)
   367 	{
   368 		ReplyToCommand(client, "[SM] Usage: sm_execcfg <filename>");
   369 		return Plugin_Handled;
   370 	}
   371 	
   372 	new String:path[64] = "cfg/";
   373 	GetCmdArg(1, path[4], sizeof(path)-4);
   374 	
   375 	if (!FileExists(path))
   376 	{
   377 		ReplyToCommand(client, "[SM] %t", "Config not found", path[4]);
   378 		return Plugin_Handled;
   379 	}
   380 	
   381 	ShowActivity(client, "%t", "Executed config", path[4]);
   382 	
   383 	LogMessage("\"%L\" executed config (file \"%s\")", client, path[4]);
   384 		
   385 	ServerCommand("exec \"%s\"", path[4]);
   386 	
   387 	return Plugin_Handled;
   388 }
   389 
   390 public Action:Command_Cvar(client, args)
   391 {
   392 	if (args < 1)
   393 	{
   394 		ReplyToCommand(client, "[SM] Usage: sm_cvar <cvar> [value]");
   395 		return Plugin_Handled;
   396 	}
   397 	
   398 	new String:cvarname[33];
   399 	GetCmdArg(1, cvarname, sizeof(cvarname));
   400 	
   401 	new Handle:hndl = FindConVar(cvarname);
   402 	if (hndl == INVALID_HANDLE)
   403 	{
   404 		ReplyToCommand(client, "[SM] %t", "Unable to find cvar", cvarname);
   405 		return Plugin_Handled;
   406 	}
   407 	
   408 	new bool:allowed = false;
   409 	if (GetConVarFlags(hndl) & FCVAR_PROTECTED)
   410 	{
   411 		/* If they're root, allow anything */
   412 		if ((GetUserFlagBits(client) & ADMFLAG_ROOT) == ADMFLAG_ROOT)
   413 		{
   414 			allowed = true;
   415 		}
   416 		/* If they're not root, and getting sv_password, see if they have ADMFLAG_PASSWORD */
   417 		else if (StrEqual(cvarname, "sv_password") && (GetUserFlagBits(client) & ADMFLAG_PASSWORD))
   418 		{
   419 			allowed = true;
   420 		}
   421 	} 
   422 	/* Do a check for the cheat cvar */
   423 	else if (StrEqual(cvarname, "sv_cheats"))
   424 	{
   425 		if (GetUserFlagBits(client) & ADMFLAG_CHEATS
   426 			|| GetUserFlagBits(client) & ADMFLAG_ROOT)
   427 		{
   428 			allowed = true;
   429 		}
   430 	}
   431 	/* If we drop down to here, it was a normal cvar. */
   432 	else
   433 	{
   434 		allowed = true;
   435 	}
   436 	
   437 	if (!allowed)
   438 	{
   439 		ReplyToCommand(client, "[SM] %t", "No access to cvar");
   440 		return Plugin_Handled;
   441 	}
   442 	
   443 	decl String:value[255];
   444 	if (args < 2)
   445 	{
   446 		GetConVarString(hndl, value, sizeof(value));
   447 		
   448 		ReplyToCommand(client, "[SM] %t", "Value of cvar", cvarname, value);
   449 		return Plugin_Handled;
   450 	}
   451 	
   452 	GetCmdArg(2, value, sizeof(value));
   453 	
   454 	if ((GetConVarFlags(hndl) & FCVAR_PROTECTED) != FCVAR_PROTECTED)
   455 	{
   456 		ShowActivity(client, "%t", "Cvar changed", cvarname, value);
   457 	} else {
   458 		ReplyToCommand(client, "[SM] %t", "Cvar changed", cvarname, value);
   459 	}
   460 	
   461 	LogMessage("\"%L\" changed cvar (cvar \"%s\") (value \"%s\")", client, cvarname, value);
   462 	
   463 	SetConVarString(hndl, value, true);
   464 		
   465 	return Plugin_Handled;
   466 }
   467 
   468 public Action:Command_Rcon(client, args)
   469 {
   470 	if (args < 1)
   471 	{
   472 		ReplyToCommand(client, "[SM] Usage: sm_rcon <args>");
   473 		return Plugin_Handled;
   474 	}
   475 	
   476 	decl String:argstring[255];
   477 	GetCmdArgString(argstring, sizeof(argstring));
   478 	
   479 	LogMessage("\"%L\" console command (cmdline \"%s\")", client, argstring);
   480 	
   481 	ServerCommand("%s", argstring);
   482 	
   483 	return Plugin_Handled;
   484 }
   485 
   486 public Action:Command_Map(client, args)
   487 {
   488 	if (args < 1)
   489 	{
   490 		ReplyToCommand(client, "[SM] Usage: sm_map <map>");
   491 		return Plugin_Handled;
   492 	}
   493 	
   494 	new String:map[64];
   495 	GetCmdArg(1, map, sizeof(map));
   496 	
   497 	if (!IsMapValid(map))
   498 	{
   499 		ReplyToCommand(client, "[SM] %t", "Map was not found", map);
   500 		return Plugin_Handled;
   501 	}
   502 	
   503 	ShowActivity(client, "%t", "Changing map", map);
   504 	
   505 	LogMessage("\"%L\" changed map to \"%s\"", client, map);
   506 	
   507 	new Handle:dp;
   508 	CreateDataTimer(3.0, Timer_ChangeMap, dp);
   509 	WritePackString(dp, map);
   510 	
   511 	return Plugin_Handled;
   512 }
   513 
   514 public Action:Timer_ChangeMap(Handle:timer, Handle:dp)
   515 {
   516 	new String:map[65];
   517 	
   518 	ResetPack(dp);
   519 	ReadPackString(dp, map, sizeof(map));
   520 	
   521 	ServerCommand("changelevel \"%s\"", map);
   522 	
   523 	return Plugin_Stop;
   524 }
   525 
   526 public Action:Command_Kick(client, args)
   527 {
   528 	if (args < 1)
   529 	{
   530 		ReplyToCommand(client, "[SM] Usage: sm_kick <#userid|name> [reason]");
   531 		return Plugin_Handled;
   532 	}
   533 	
   534 	new String:arg[65];
   535 	GetCmdArg(1, arg, sizeof(arg));
   536 	
   537 	new clients[2];
   538 	new numClients = SearchForClients(arg, clients, 2);
   539 	
   540 	if (numClients == 0)
   541 	{
   542 		ReplyToCommand(client, "[SM] %t", "No matching client");
   543 		return Plugin_Handled;
   544 	} else if (numClients > 1) {
   545 		ReplyToCommand(client, "[SM] %t", "More than one client matches", arg);
   546 		return Plugin_Handled;
   547 	} else if (!CanUserTarget(client, clients[0])) {
   548 		ReplyToCommand(client, "[SM] %t", "Unable to target");
   549 		return Plugin_Handled;
   550 	}
   551 	
   552 	new userid = GetClientUserId(clients[0]);
   553 	new String:name[65];
   554 	
   555 	GetClientName(clients[0], name, sizeof(name));
   556 	
   557 	decl String:reason[256];
   558 	if (args < 2)
   559 	{
   560 		/* Safely null terminate */
   561 		reason[0] = '\0';
   562 	} else {
   563 		GetCmdArg(2, reason, sizeof(reason));
   564 	}
   565 	
   566 	ShowActivity(client, "%t", "Kicked player", name);
   567 	
   568 	LogMessage("\"%L\" kicked \"%L\" (reason \"%s\")", client, clients[0], reason);
   569 	
   570 	if (args < 2)
   571 	{
   572 		ServerCommand("kickid %d", userid);
   573 	} else {
   574 		ServerCommand("kickid %d \"%s\"", userid, reason);
   575 	}
   576 	
   577 	return Plugin_Handled;
   578 }