· 8 years ago · Aug 21, 2018, 02:58 PM
1/* [CS:S/CS:GO] CT Bans
2 Copyright (C) 2011-2017 by databomb
3
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17 ***************************************************************************
18
19 Description:
20 Allows admins to restrict access to the CT team from those who violate the server's rules. Designed for specific usage in Jailbreak environments.
21
22 Features:
23 - CT Bans are stored in the ClientPrefs database and survive map changes, re-joins, and server crashes.
24 - The Rage Ban feature allows admins to CT ban rage quitters who break the server's rules and then quickly disconnect.
25 - You may give a timed CT ban which will work based on in minutes spent alive (so idlers in spectate or those who suicide at the beginning of the round will not be working toward an unban.)
26 - The timed CT bans are stored in a SQL table for stateful access.
27 - The plugin logs CT ban to a SQL table in addition to your regular SM logs.
28 - Re-displays the team selection screen after an improper selection was made.
29 - SM Menu integration for the rageban and ctban commands.
30 - Displays helpful message to users who are CT banned when they join the server.
31 - SM Translations support.
32 - Custom reasons permitted (configs/ctban_reasons.ini).
33 - Custom lengths permitted (configs/ctban_times.ini).
34
35 Installation:
36 Place the ctban.phrases.txt file in your addons/sourcemod/translations directory.
37 Place the sm_ctban.smx file in your addons/sourcemod/plugins directory.
38 Check your logs/server-console after the initial load for any SQL errors. If you have any SQL errors check your addons/sourcemod/configs/databases.cfg file and verify you can connect using the drivers you have specified.
39 Upgrade: Delete cfg/sourcemod/ctban.cfg and re-configure convars after the file is re-created.
40 Optional: Generate custom reasons list by creating a simple text file (addons/sourcemod/configs/ctban_reasons.ini) with 1 reason per line.
41
42 Command Usage:
43
44 sm_ctban <player> <time> <optional: reason>
45 Bans the selected player from joining the CT team.
46
47 sm_removectban <player> | sm_unctban <player>
48 Removes the CT ban on the selected player.
49
50 sm_isbanned <player>
51 Reports back the status of the current player's CT ban and the time remaining on the ban, if any.
52
53 sm_rageban
54 Brings up a menu so you may choose a recently disconnected player to permanently CT ban.
55
56 sm_ctban_offline <steamid>
57 Bans the given Steam Id from playing on the CT team.
58
59 sm_removectban_offline <steamid> | sm_unctban_offline <steamid>
60 Unbans the given Steam Id from the CT team.
61
62 sm_reset_ctban_cookies <'force'>
63 Resets the entire CTBan cookie database.
64
65 sm_forcect <player>
66 Overrides any CTBans and swaps a player to CT team.
67
68 sm_unforcect <player>
69 Removes overrides and moves player to T team.
70
71 sm_isbanned_offline <steamid>
72 Reports back the status of the target Steam Id from the ban database.
73
74 sm_change_ctban_time <player> <time>
75 Changes an existing CTBan to the new time specified. 0 would be permanently CTBan.
76
77 sm_ctbanlist
78 Displays a menu of active players who are CT Banned.
79
80 Settings:
81 sm_ctban_soundfile, <path>: The path to the soundfile to play when denying a team-change request. Set to "" to disable.
82 sm_ctban_joinbanmsg, <message>: This message is appended to a time-stamp when a CT banned user joins the server.
83 sm_ctban_table_prefix, <prefix>: This prefix will be added in front of the table names.
84 sm_ctban_database_driver, <driver>: This specifies which driver to use from database.cfg
85 sm_ctban_force_reason, [0,1]: Specifies whether a reason is required for the CT Ban command.
86 sm_ctban_checkctbans_adminflags, [a-z]: Specifies the admin flag levels that may use the !ctbanlist and !isbanned command targeting anyone. Blank allows all players access on everyone.
87 sm_ctban_isbanned_selftarget, [0,1]: Specifies whether a non-admin can target themselves using the !isbanned command.
88 sm_ctban_respawn, [0,1]: Specifies whether to respawn players after team changes.
89
90 Special Thanks (Development):
91 Azelphur for snippets of cross-mod code.
92 Kigen for the idea of CT banning based on time spent alive.
93 oaaron99 for the idea of smart !ctban menu re-directs.
94 Bara for include file ideas and lengths code.
95
96 Future Considerations:
97 Using API-- Steam Group CTBans
98 Using API-- New Admin Level and Command for CT Banning for Only Small Durations
99
100 Change Log:
101 2.0.3 Adds !rageban console user support. Fixed bug where !rageban was not permanent. Fixed bug with custom times (configs/ctban_times.ini) not displaying menu options correctly.
102 Adds multi-targeting filters for other admin commands: @ctban @!ctban and @noctbans (@noctbans specifies players who have never had a CT Ban).
103 2.0.2 Adds SQLite support. Updated include file: Adds more intelligent #tryinclude and pre-compile directives.
104 Alerts admins if someone is swapped to CT without !forcect. Added custom times options (configs/ctban_times.ini).
105 Times file should be formatted as a Key Values file with each section having the number of minutes and a description such as: "90" "1 Hour 30 Minutes"
106 2.0.1 Bug fixes in UnForceCT, ForceCT, and OnClientAuthorized which were each generating errors.
107 2.0.0 Ported to the new syntax. Translation file updated. CS:GO Fixes bug where mp_force_pick_time could assign a banned player to CT. Made !ctban open menus if more info is needed.
108 CS:GO Fixes incompatibility with Zephyrus's Team Limit Bypass plugin. Adds spawn check to verify CTBans. Added !forcect/!unforcect to override CTBan and swap players.
109 Allows custom reasons (configs/ctban_reasons.ini). Allows non-admins to use !isbanned. Added command to reset all CT Ban cookies. Added Player Commands menu for !unctban.
110 Adds CT Ban to !admin Player Commands menu. Allowed fallback for !isbanned to return ban info even if database log entries were missing. Added !ctbanlist command.
111 Added CT Ban reason to !ctban chat output where possible. Changed from [SM] to [CTBAN] chat tag and added colors. Removing compile option USESQL (Now Always Uses SQL).
112 Added !isbanned_offline to find CT Ban info of offline players. !ctban_offline and !unctban_offline now update the log database records.
113 Added convar sm_ctban_respawn to allow respawns after team swaps due to !ctban or !forcect. Added !change_ctban_time command to edit the time remaining on CTBans.
114 Added API (ctban.inc) for 3rd-party plugin interfaces. The convar sm_ctban_enable is being removed (disable the plugin to disable functionality).
115 Upgraded database log table to include an auto incrementing primary key (ban_id) -- automatically upgrades from tables.
116 Added check for enforcing CTBans if the plugin is loaded late.
117 1.6.2 Translation file updated. Added admin, time, reason information for !isbanned. Show !rageban results in chat to players. Added ConVar for forcing !ctban reason.
118 1.6.1.4 Fixed bug preventing console CT bans (thanks Kailo!)
119 1.6.1.3 Fixed bug with EscapeString function which caused query failures
120 1.6.1.2 Fixed SQL Injection vulnerability
121 1.6.1.1 Fixed problem in UTIL_TeamMenu()
122 1.6.1 Support for new SM1.4 natives, Added config file generation
123 1.6.0 Added support for new SM1.4 natives
124 1.5.0 Initial public release
125 1.4.4 Stable internal build
126*/
127
128// Compilation Settings
129//#define CTBAN_DEBUG
130
131#define PLUGIN_VERSION "2.0.3"
132
133#include <sourcemod>
134#include <clientprefs>
135#include <sdktools>
136#include <adminmenu>
137#include <cstrike>
138#include <multicolors>
139#include <multicolors/morecolors>
140#include <multicolors/colors>
141
142#tryinclude <hosties>
143#tryinclude <ctban>
144
145#if !defined _CTBan_Included_
146
147 // Common constant verifications
148 #if !defined INVALID_WEAPON
149 #define INVALID_WEAPON -1
150 #else
151 #assert INVALID_WEAPON == -1
152 #endif
153 #if !defined ZERO
154 #define ZERO 0
155 #else
156 #assert ZERO == 0
157 #endif
158 #if !defined ONE
159 #define ONE 1
160 #else
161 #assert ONE == 1
162 #endif
163 #if !defined TWO 2
164 #define TWO 2
165 #else
166 #assert TWO == 2
167 #endif
168 #if !defined THREE
169 #define THREE 3
170 #else
171 #assert THREE == 3
172 #endif
173 #if !defined FOUR
174 #define FOUR 4
175 #else
176 #assert FOUR == 4
177 #endif
178 #if !defined FIVE
179 #define FIVE 5
180 #else
181 #assert FIVE == 5
182 #endif
183 #if !defined SIX
184 #define SIX 6
185 #else
186 #assert SIX == 6
187 #endif
188 #if !defined SEVEN
189 #define SEVEN 7
190 #else
191 #assert SEVEN == 7
192 #endif
193
194 // General constants
195 #define VALUE_NOT_FOUND_IN_ARRAY -1
196 #define SUBSTRING_NOT_FOUND -1
197 #define RAGEBAN_ADMIN_LEVEL ADMFLAG_SLAY
198 #define CTBAN_ADMIN_LEVEL ADMFLAG_SLAY
199 #define UNCTBAN_ADMIN_LEVEL ADMFLAG_SLAY
200 #define FORCECT_ADMIN_LEVEL ADMFLAG_SLAY
201 #define UNFORCECT_ADMIN_LEVEL ADMFLAG_SLAY
202 #define JOINFAILREASON_ONECHANGE 0
203 #define MENUCHOICE_USERID 0
204 #define MENUCHOICE_TIME 1
205 #define CALLER_NATIVE -2
206 #define COOKIE_BANNED_STRING "1"
207 #define COOKIE_UNBANNED_STRING "0"
208 #define ARG_ZERO_GET_COMMAND_NAME 0
209 #define FORCECT_ARG_TARGET 1
210 #define UNFORCECT_ARG_TARGET 1
211 #define ISBANNED_ARG_TARGET 1
212 #define CTBAN_ARG_PLAYER 1
213 #define CTBAN_ARG_TIME 2
214 #define CTBAN_ARG_REASON 3
215 #define CTBAN_NO_REASON_GIVEN -1
216 #define CTBAN_PERM_BAN_LENGTH 0
217 #define RAGEBAN_ARG_CONSOLE_TARGET 1
218 #define UNCTBAN_ARG_TARGET 1
219 #define CHANGE_TIME_ARG_TARGET 1
220 #define CHANGE_TIME_ARG_TIME 2
221 #define JOINTEAM_ARG_TEAM_STRING 1
222 #define CLIENT_DISCONNECT_CB_FIELD_TIMELEFT 0
223 #define FIND_COOKIE_CB_FIELD_COOKIE_ID 0
224 #define CLIENT_AUTHED_CB_FIELD_TIMELEFT 0
225 #define ISBANNED_CB_FIELD_TIMESTAMP 0
226 #define ISBANNED_CB_FIELD_ADMINNAME 1
227 #define ISBANNED_CB_FIELD_REASON 2
228 #define ISBANNED_OFF_CB_FIELD_TIMESTAMP 0
229 #define ISBANNED_OFF_CB_FIELD_ADMINNAME 1
230 #define ISBANNED_OFF_CB_FIELD_REASON 2
231 #define ISBANNED_OFF_CB_FIELD_TIMELEFT 3
232 #define ISBANNED_OFF_CB_FIELD_PERPNAME 4
233 #define NATIVE_ISBANNED_CELL_CLIENT 1
234 #define NATIVE_GET_TIMELEFT_CELL_CLIENT 1
235 #define NATIVE_GET_OVERRIDE_CELL_CLIENT 1
236 #define NATIVE_GETBANINFO_CELL_CLIENT 1
237 #define NATIVE_GETBANINFO_OFF_STR_AUTHID 1
238 #define NATIVE_CTBAN_CELL_CLIENT 1
239 #define NATIVE_CTBAN_CELL_TIME 2
240 #define NATIVE_CTBAN_CELL_ADMIN 3
241 #define NATIVE_CTBAN_STR_REASON 4
242 #define NATIVE_CTBAN_OFF_STR_AUTHID 1
243 #define NATIVE_CHANGE_TIME_CELL_CLIENT 1
244 #define NATIVE_CHANGE_TIME_CELL_TIME 2
245 #define NATIVE_CHANGE_TIME_CELL_ADMIN 3
246 #define NATIVE_UNBAN_CELL_CLIENT 1
247 #define NATIVE_UNBAN_CELL_ADMIN 2
248 #define NATIVE_UNBAN_OFF_STR_AUTHID 1
249 #define NATIVE_FORCECT_CELL_CLIENT 1
250 #define NATIVE_FORCECT_CELL_ADMIN 2
251 #define NATIVE_UNFORCECT_CELL_CLIENT 1
252 #define NATIVE_UNFORCECT_CELL_ADMIN 2
253 #define NATIVE_MIN_AUTHID_LENGTH 3
254 #define FIELD_AUTHID_MAXLENGTH 22
255 #define FIELD_NAME_MAXLENGTH 32
256 #define FIELD_REASON_MAXLENGTH 200
257 #define QUERY_MAXLENGTH 350
258 #define COOKIE_INIT_CHECK_TIME 0.0
259 #define COOKIE_RESCAN_TIME 5.0
260 #define DELAY_ENFORCEMENT_TIME 1.8
261 #define AUTH_RESCAN_TIME 4.0
262 #define DECREMENT_TIMEBAN_INTERVAL 60.0
263 #define PLAY_COMMAND_STRING "play "
264 #define PLAY_COMMAND_STRING_LENGTH 5
265 #define CSGO_MAX_PAGE_MENU_ITEMS 6
266 #define CSS_MAX_PAGE_MENU_ITEMS 7
267 #define CTBAN_COMMAND "sm_ctban"
268 #define REMOVECTBAN_COMMAND "sm_removectban"
269 #define RAGEBAN_COMMAND "sm_rageban"
270 #define FORCECT_COMMAND "sm_forcect"
271 #define UNFORCECT_COMMAND "sm_unforcect"
272 #define MAX_UNBAN_CMD_LENGTH 16
273 #define MAX_TABLE_LENGTH 32
274 #define MAX_DEFAULT_TABLE_LENGTH 12
275 #define MAX_CHAT_BANNER_LENGTH 36
276 #define MAX_RESET_ARG_LENGTH 10
277 #define MAX_USERID_LENGTH 32
278 #define MAX_COOKIE_STR_LENGTH 7
279 #define MAX_JOINTEAM_ARG_LENGTH 5
280 #define MAX_TIME_ARG_LENGTH 32
281 #define MAX_TIME_INFO_STR_LENGTH 150
282 #define MAX_JOIN_BAN_MSG_LENGTH 100
283 #define MAX_ADMINFLAGS_LENGTH 27
284 #define MAX_REASON_MENU_CHOICE_LENGTH 10
285 #define MAX_MENU_INT_CHOICE_LENGTH 4
286 #define MAX_DATABASE_ID_LENGTH 7
287 #define CTBAN_ADMIN_IS_CONSOLE 0
288 #define CONSOLE_USER_NAME "Console"
289 #define CONSOLE_AUTHID "STEAM_0:1:1"
290 #define RAGEBAN_LOG_REASON "Rage ban"
291 #define OFFLINE_NAME_UNAVAILBLE "Unavailable"
292 #define REASON_OFFLINECTBAN "Offline AuthId Ban"
293 #define CALLER_DO_NOT_REPLY -1
294
295 // Pre-processor macros
296 #define MAX_SAFE_ESCAPE_QUERY(%1) (TWO*(%1)+ONE)
297
298#endif
299
300// SQL Queries
301#define CTBAN_QUERY_CP_FIND_COOKIE_ID "SELECT id FROM sm_cookies WHERE name = 'Banned_From_CT'"
302#define CTBAN_QUERY_CP_SELECT_BAN_COOKIE "SELECT value FROM sm_cookie_cache WHERE player = '%s' and cookie_id = '%i'"
303#define CTBAN_QUERY_CP_RESET_COOKIES "UPDATE sm_cookie_cache SET value = '' WHERE cookie_id = '%i'"
304
305#define CTBAN_QUERY_TIME_CREATE "CREATE TABLE IF NOT EXISTS %s (steamid VARCHAR(%d), ctbantime INT(16), PRIMARY KEY (steamid))"
306#define CTBAN_QUERY_TIME_SELECT_BANTIME "SELECT ctbantime FROM %s WHERE steamid = '%s'"
307#define CTBAN_QUERY_TIME_INSERT_SQLITE "INSERT OR REPLACE INTO %s (steamid, ctbantime) VALUES ('%s', %d)"
308#define CTBAN_QUERY_TIME_INSERT_MYSQL "INSERT INTO %s (steamid, ctbantime) VALUES ('%s', %d) ON DUPLICATE KEY UPDATE ctbantime=%d"
309#define CTBAN_QUERY_TIME_UPDATE "UPDATE %s SET ctbantime = %d WHERE steamid = '%s'"
310#define CTBAN_QUERY_TIME_DELETE "DELETE FROM %s WHERE steamid = '%s'"
311
312#define CTBAN_QUERY_LOG_CREATE "CREATE TABLE IF NOT EXISTS %s (ban_id INT UNSIGNED AUTO_INCREMENT, timestamp INT, perp_steamid VARCHAR(%d), perp_name VARCHAR(%d), admin_steamid VARCHAR(%d), admin_name VARCHAR(%d), bantime INT(16), timeleft INT(16), reason VARCHAR(%d), PRIMARY KEY (ban_id))"
313#define CTBAN_QUERY_LOG_INSERT "INSERT INTO %s (timestamp, perp_steamid, perp_name, admin_steamid, admin_name, bantime, timeleft, reason) VALUES (%d, '%s', '%s', '%s', '%s', %d, %d, '%s')"
314#define CTBAN_QUERY_LOG_ISBANNED "SELECT timestamp, admin_name, reason FROM %s WHERE perp_steamid = '%s' AND timeleft >= 0 ORDER BY timestamp DESC LIMIT 1"
315#define CTBAN_QUERY_LOG_ISBANNED_OFFLINE "SELECT timestamp, admin_name, reason, timeleft, perp_name FROM %s WHERE perp_steamid = '%s' AND timeleft >= 0 ORDER BY timestamp DESC LIMIT 1"
316#define CTBAN_QUERY_LOG_EXPIRE "UPDATE %s SET timeleft=-1 WHERE perp_steamid = '%s' and timeleft >= 0"
317#define CTBAN_QUERY_LOG_V1_CHECK "SELECT ban_id FROM %s LIMIT 1"
318#define CTBAN_QUERY_LOG_TO_V2_DROPKEY "ALTER TABLE %s DROP PRIMARY KEY"
319#define CTBAN_QUERY_LOG_TO_V2_ADD_BANID "ALTER TABLE %s ADD ban_id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT FIRST"
320#define CTBAN_QUERY_LOG_UPDATE "UPDATE %s SET timeleft = %d WHERE perp_steamid = '%s' AND timeleft >= 0"
321#define CTBAN_QUERY_LOG_TIME_TO_PERM_MYSQL "UPDATE %s SET (bantime, timeleft) VALUES (0, 0) WHERE perp_steamid = '%s' AND timeleft > 0"
322#define CTBAN_QUERY_LOG_TIME_TO_PERM_SQLITE "UPDATE %s SET bantime = 0, timeleft = 0 WHERE perp_steamid = '%s' AND timeleft > 0"
323#define CTBAN_QUERY_LOG_PERM_TO_TIME_MYSQL "UPDATE %s SET (bantime, timeleft) VALUES (%d, %d) WHERE perp_steamid = '%s' AND timeleft = 0 AND bantime = 0"
324#define CTBAN_QUERY_LOG_PERM_TO_TIME_SQLITE "UPDATE %s SET bantime = %d, timeleft = %d WHERE perp_steamid = '%s' AND timeleft = 0 AND bantime = 0"
325
326#pragma semicolon 1
327#pragma newdecls required
328
329char g_sChatBanner[MAX_CHAT_BANNER_LENGTH];
330EngineVersion g_EngineVersion = Engine_Unknown;
331Handle g_CT_Cookie = INVALID_HANDLE;
332Handle gH_TopMenu = INVALID_HANDLE;
333Handle gH_Cvar_SoundName = INVALID_HANDLE;
334char gS_SoundPath[PLATFORM_MAX_PATH];
335Handle gH_Cvar_JoinBanMessage = INVALID_HANDLE;
336Handle gH_Cvar_Database_Driver = INVALID_HANDLE;
337Handle gA_DNames = INVALID_HANDLE;
338Handle gA_DSteamIDs = INVALID_HANDLE;
339Handle gH_CP_DataBase = INVALID_HANDLE;
340Handle gH_BanDatabase = INVALID_HANDLE;
341Handle gH_Cvar_Table_Prefix = INVALID_HANDLE;
342int g_iCookieIndex;
343bool g_bAuthIdNativeExists = false;
344Handle gA_TimedBanLocalList = INVALID_HANDLE;
345int gA_LocalTimeRemaining[MAXPLAYERS+ONE];
346char g_sLogTableName[MAX_TABLE_LENGTH];
347char g_sTimesTableName[MAX_TABLE_LENGTH];
348Handle gH_Cvar_Force_Reason = INVALID_HANDLE;
349Handle gH_DArray_Reasons = INVALID_HANDLE;
350Handle gH_KV_BanLengths = INVALID_HANDLE;
351Handle gH_Cvar_CheckCTBans_Flags = INVALID_HANDLE;
352Handle gH_Cvar_IsBanned_Self = INVALID_HANDLE;
353Handle gH_Cvar_Respawn = INVALID_HANDLE;
354bool g_bA_Temp_CTBan_Override[MAXPLAYERS+ONE];
355bool g_bIgnoreOverrideResets;
356bool g_bRageBanArrayChanged;
357
358Handle g_hFrwd_OnForceCT = INVALID_HANDLE;
359Handle g_hFrwd_OnUnforceCT = INVALID_HANDLE;
360Handle g_hFrwd_OnCTBan_Offline = INVALID_HANDLE;
361Handle g_hFrwd_OnUnCTBan_Offline = INVALID_HANDLE;
362Handle g_hFrwd_OnCTBan = INVALID_HANDLE;
363Handle g_hFrwd_OnUnCTBan = INVALID_HANDLE;
364Handle g_hFrwd_CTBanInfo = INVALID_HANDLE;
365Handle g_hFrwd_CTBanInfoOffline = INVALID_HANDLE;
366
367enum eCTBanMenuHandler
368{
369 e_RemoveCTBan=ZERO,
370 e_CTBanList=ONE,
371 e_ForceCT=TWO
372}
373
374enum eQueryCallback
375{
376 e_QueryLogTableTwo=ZERO
377}
378
379enum eDatabaseType
380{
381 e_Unknown=ZERO,
382 e_MySQL=ONE,
383 e_SQLite=TWO
384}
385
386eDatabaseType g_eDatabaseType = e_Unknown;
387
388public Plugin myinfo =
389{
390 name = "CT Ban",
391 author = "databomb",
392 description = "Allows admins to ban players from joining the CT team.",
393 version = PLUGIN_VERSION,
394 url = "https://forums.alliedmods.net/showthread.php?t=166080"
395};
396
397public APLRes AskPluginLoad2(Handle hMyself, bool bLate, char[] sError, int iErr_Max)
398{
399 g_EngineVersion = GetEngineVersion();
400
401 SetCTBanChatBanner(g_EngineVersion, g_sChatBanner);
402
403 RegPluginLibrary("ctban");
404
405 CreateForwards();
406 CreateNatives();
407
408 return APLRes_Success;
409}
410
411public void OnPluginStart()
412{
413 CreateConVar("sm_ctban_version", PLUGIN_VERSION, "CT Ban Version", FCVAR_SPONLY|FCVAR_DONTRECORD|FCVAR_REPLICATED|FCVAR_NOTIFY);
414 gH_Cvar_SoundName = CreateConVar("sm_ctban_soundfile", "buttons/button11.wav", "The name of the sound to play when an action is denied.", FCVAR_NONE);
415 gH_Cvar_JoinBanMessage = CreateConVar("sm_ctban_joinbanmsg", "Contact an admin if you would like to request an unban.", "This text is appended to the time the user was last CT banned when they join T or Spectator teams.", FCVAR_NONE);
416 gH_Cvar_Table_Prefix = CreateConVar("sm_ctban_table_prefix", "", "Adds a prefix to the CT Bans table, leave this blank unless you have a need to add a prefix for multiple servers on one database.", FCVAR_NONE);
417 gH_Cvar_Database_Driver = CreateConVar("sm_ctban_database_driver", "default", "Specifies the configuration driver to use from SourceMod's database.cfg", FCVAR_NONE);
418 gH_Cvar_Force_Reason = CreateConVar("sm_ctban_force_reason", "0", "Specifies whether to force admins to specify a reason when using CTBan command", FCVAR_NONE);
419 gH_Cvar_CheckCTBans_Flags = CreateConVar("sm_ctban_checkctbans_adminflags", "bz", "The admin flag(s) that may use !isbanned command on anyone. Blank allows all players access on anyone.", FCVAR_NONE);
420 gH_Cvar_IsBanned_Self = CreateConVar("sm_ctban_isbanned_selftarget", "0", "Specifies whether to allow non-admins to use !isbanned on themselves.", FCVAR_NONE);
421 gH_Cvar_Respawn = CreateConVar("sm_ctban_respawn", "0", "Specifies whether players are respawned after being team changed.", FCVAR_NONE);
422
423 AutoExecConfig(true, "ctban");
424
425 g_CT_Cookie = RegClientCookie("Banned_From_CT", "Tells if you are restricted from joining the CT team", CookieAccess_Protected);
426
427 RegConsoleCmd("sm_isbanned", Command_IsBanned, "sm_isbanned <player> - Lets you know if a player is banned from CT team.");
428 RegConsoleCmd("sm_ctbanlist", Command_CTBanList, "sm_ctbanlist - Displays a list of active players who are CT Banned.");
429
430 RegAdminCmd(CTBAN_COMMAND, Command_CTBan, CTBAN_ADMIN_LEVEL, "sm_ctban <player> <time> <optional: reason> - Bans a player from being a CT.");
431 RegAdminCmd(REMOVECTBAN_COMMAND, Command_UnCTBan, UNCTBAN_ADMIN_LEVEL, "sm_removectban <player> - Unrestricts a player from being a CT.");
432 RegAdminCmd("sm_unctban", Command_UnCTBan, UNCTBAN_ADMIN_LEVEL, "sm_unctban <player> - Unrestricts a player from being a CT.");
433 RegAdminCmd(RAGEBAN_COMMAND, Command_RageBan, RAGEBAN_ADMIN_LEVEL, "sm_rageban <player> - Allows you to ban those who rage quit.");
434 RegAdminCmd("sm_ctban_offline", Command_Offline_CTBan, ADMFLAG_KICK, "sm_ctban_offline <steamid> - Allows admins to CT Ban players who have long left the server using their Steam Id.");
435 RegAdminCmd("sm_unctban_offline", Command_Offline_UnCTBan, ADMFLAG_KICK, "sm_unctban_offline <steamid> - Allows admins to remove CT Bans on players who have long left the server using their Steam Id.");
436 RegAdminCmd("sm_removectban_offline", Command_Offline_UnCTBan, ADMFLAG_KICK, "sm_unctban_offline <steamid> - Allows admins to remove CT Bans on players who have long left the server using their Steam Id.");
437 RegAdminCmd("sm_reset_ctban_cookies", Command_ResetCookies, ADMFLAG_ROOT, "sm_reset_ctban_cookies <'force'> - Allows the admin to reset all CTBan cookies to be unbanned.");
438 RegAdminCmd(FORCECT_COMMAND, Command_ForceCT, FORCECT_ADMIN_LEVEL, "sm_forcect <player> - Temporarily overrides CTBan status and swaps player to CT team.");
439 RegAdminCmd(UNFORCECT_COMMAND, Command_UnForceCT, UNFORCECT_ADMIN_LEVEL, "sm_unforcect <player> - Removes any temporary overrides and removes player from CT team.");
440 RegAdminCmd("sm_isbanned_offline", Command_Offline_IsBanned, ADMFLAG_SLAY, "sm_isbanned_offline <steamid> - Allows admins to get CT Ban information on offline players user their Steam Id.");
441 RegAdminCmd("sm_change_ctban_time", Command_Change_CTBan_Time, ADMFLAG_KICK, "sm_change_ctban_time <player> <time> - Allows the admin to change the time remaining for an existing CTBan.");
442
443 LoadTranslations("ctban.phrases");
444 LoadTranslations("common.phrases");
445 LoadTranslations("clientprefs.phrases");
446 LoadTranslations("core.phrases");
447
448 // create arrays for the rage bans
449 gA_DNames = CreateArray(MAX_TARGET_LENGTH);
450 gA_DSteamIDs = CreateArray(22);
451 g_iCookieIndex = ZERO;
452
453 // Hook this to block joins when player is banned
454 AddCommandListener(Command_CheckJoin, "jointeam");
455 // This is the only sane way to deal with CS:GO auto-assign and plugin conflicts as in CS:GO Team Limit Bypass
456 HookEvent("player_spawn", Event_PlayerSpawn, EventHookMode_Post);
457 // This will catch anyone that gets swapped manually
458 HookEvent("player_team", Event_PlayerTeam, EventHookMode_Post);
459
460 // create local array for timed bans
461 // block 0: client index
462 gA_TimedBanLocalList = CreateArray(2);
463 char sAuthID[FIELD_AUTHID_MAXLENGTH];
464 for (int iIndex = ONE; iIndex <= MaxClients; iIndex++)
465 {
466 gA_LocalTimeRemaining[iIndex] = ZERO;
467
468 // Check if we need to remove anyone from CT team immediately
469 if (IsClientInGame(iIndex))
470 {
471 if (GetClientTeam(iIndex) == CS_TEAM_CT && GetCTBanStatus(iIndex))
472 {
473 EnforceCTBan(iIndex);
474
475 // Gather the time component, if needed
476 if (IsClientAuthorized(iIndex))
477 {
478 GetClientAuthId(iIndex, AuthId_Steam2, sAuthID, sizeof(sAuthID));
479 OnClientAuthorized(iIndex, sAuthID);
480 }
481 }
482 }
483 }
484
485 // periodic timer to handle timed bans
486 CreateTimer(DECREMENT_TIMEBAN_INTERVAL, Timer_CheckTimedCTBans, _, TIMER_REPEAT);
487
488 // Account for late loading
489 Handle hTopMenu;
490 if (LibraryExists("adminmenu") && ((hTopMenu = GetAdminTopMenu()) != INVALID_HANDLE))
491 {
492 OnAdminMenuReady(hTopMenu);
493 }
494
495 gH_DArray_Reasons = CreateArray(FIELD_REASON_MAXLENGTH);
496
497 if (g_EngineVersion == Engine_CSGO)
498 {
499 HookEvent("jointeam_failed", Event_JoinTeamFailed, EventHookMode_Pre);
500 }
501
502 AddMultiTargetFilter("@ctban", Filter_CTBanned_Players, "CT Banned Players", false);
503 AddMultiTargetFilter("@!ctban", Filter_NotCTBanned_Players, "Players without a CT Ban", false);
504 AddMultiTargetFilter("@noctbans", Filter_NeverCTBanned_Players, "Players who have never had a CT Ban", false);
505}
506
507public bool Filter_CTBanned_Players(const char[] sPattern, Handle hClients)
508{
509 for (int iIndex = ONE; iIndex <= MaxClients; iIndex++)
510 {
511 if (IsClientInGame(iIndex))
512 {
513 if (GetCTBanStatus(iIndex))
514 {
515 PushArrayCell(hClients, iIndex);
516 }
517 }
518 }
519
520 return true;
521}
522
523public bool Filter_NotCTBanned_Players(const char[] sPattern, Handle hClients)
524{
525 for (int iIndex = ONE; iIndex <= MaxClients; iIndex++)
526 {
527 if (IsClientInGame(iIndex))
528 {
529 if (!GetCTBanStatus(iIndex))
530 {
531 PushArrayCell(hClients, iIndex);
532 }
533 }
534 }
535
536 return true;
537}
538
539public bool Filter_NeverCTBanned_Players(const char[] sPattern, Handle hClients)
540{
541 for (int iIndex = ONE; iIndex <= MaxClients; iIndex++)
542 {
543 if (IsClientInGame(iIndex))
544 {
545 if (AreClientCookiesCached(iIndex))
546 {
547 char sCookie[MAX_COOKIE_STR_LENGTH];
548 GetClientCookie(iIndex, g_CT_Cookie, sCookie, sizeof(sCookie));
549
550 if (!strlen(sCookie))
551 {
552 PushArrayCell(hClients, iIndex);
553 }
554 }
555 }
556 }
557
558 return true;
559}
560
561void CreateNatives()
562{
563 CreateNative("CTBan_IsClientBanned", Native_IsClientBanned);
564 CreateNative("CTBan_GetTimeRemaining", Native_GetTimeRemaining);
565 CreateNative("CTBan_GetOverrideStatus", Native_GetOverrideStatus);
566 CreateNative("CTBan_GetBanInfo", Native_GetBanInfo);
567 CreateNative("CTBan_GetBanInfo_Offline", Native_GetBanInfo_Offline);
568
569 CreateNative("CTBan_Client", Native_CTBan_Client);
570 CreateNative("CTBan_Client_Offline", Native_CTBan_Client_Offline);
571 CreateNative("CTBan_ChangeBanLength", Native_CTBan_ChangeBanLength);
572
573 CreateNative("CTBan_UnbanClient", Native_CTBan_UnbanClient);
574 CreateNative("CTBan_UnbanClient_Offline", Native_CTBan_UnbanClient_Offline);
575
576 CreateNative("CTBan_ForceCT", Native_CTBan_ForceCT);
577 CreateNative("CTBan_UnForceCT", Native_CTBan_UnForceCT);
578}
579
580void CreateForwards()
581{
582 g_hFrwd_OnForceCT = CreateGlobalForward("CTBan_OnForceCT", ET_Ignore, Param_Cell, Param_Cell);
583 g_hFrwd_OnUnforceCT = CreateGlobalForward("CTBan_OnUnforceCT", ET_Ignore, Param_Cell, Param_Cell);
584
585 g_hFrwd_OnCTBan = CreateGlobalForward("CTBan_OnClientBan", ET_Ignore, Param_Cell, Param_Cell, Param_Cell, Param_String);
586 g_hFrwd_OnCTBan_Offline = CreateGlobalForward("CTBan_OnClientBan_Offline", ET_Ignore, Param_String, Param_Cell);
587
588 g_hFrwd_OnUnCTBan = CreateGlobalForward("CTBan_OnClientUnban", ET_Ignore, Param_Cell, Param_Cell);
589 g_hFrwd_OnUnCTBan_Offline = CreateGlobalForward("CTBan_OnClientUnban_Offline", ET_Ignore, Param_String, Param_Cell);
590
591 g_hFrwd_CTBanInfo = CreateGlobalForward("CTBan_GetBanInfoReturn", ET_Ignore, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_String, Param_String);
592 g_hFrwd_CTBanInfoOffline = CreateGlobalForward("CTBan_GetOfflineBanInfoReturn", ET_Ignore, Param_Cell, Param_String, Param_Cell, Param_Cell, Param_String, Param_String, Param_String);
593}
594
595public int Native_IsClientBanned(Handle hPlugin, int iParams)
596{
597 int iClient = GetNativeCell(NATIVE_ISBANNED_CELL_CLIENT);
598
599 if (iClient <= ZERO || iClient > MaxClients || !IsClientInGame(iClient))
600 {
601 ThrowNativeError(SP_ERROR_NATIVE, "Client (%d) is invalid!", iClient);
602 return ZERO;
603 }
604
605 return GetCTBanStatus(iClient);
606}
607
608public int Native_GetTimeRemaining(Handle hPlugin, int iParams)
609{
610 int iClient = GetNativeCell(NATIVE_GET_TIMELEFT_CELL_CLIENT);
611
612 if (iClient <= ZERO || iClient > MaxClients || !IsClientInGame(iClient))
613 {
614 ThrowNativeError(SP_ERROR_NATIVE, "Client (%d) is invalid!", iClient);
615 }
616
617 return gA_LocalTimeRemaining[iClient];
618}
619
620public int Native_GetOverrideStatus(Handle hPlugin, int iParams)
621{
622 int iClient = GetNativeCell(NATIVE_GET_OVERRIDE_CELL_CLIENT);
623
624 if (iClient <= ZERO || iClient > MaxClients || !IsClientInGame(iClient))
625 {
626 ThrowNativeError(SP_ERROR_NATIVE, "Client (%d) is invalid!", iClient);
627 return false;
628 }
629
630 return g_bA_Temp_CTBan_Override[iClient];
631}
632
633public int Native_GetBanInfo(Handle hPlugin, int iParams)
634{
635 int iClient = GetNativeCell(NATIVE_GETBANINFO_CELL_CLIENT);
636
637 if (iClient <= ZERO || iClient > MaxClients || !IsClientInGame(iClient))
638 {
639 ThrowNativeError(SP_ERROR_NATIVE, "Client (%d) is invalid!", iClient);
640 }
641
642 ProcessIsBannedTarget(iClient, CALLER_NATIVE);
643
644 return SP_ERROR_NONE;
645}
646
647public int Native_GetBanInfo_Offline(Handle hPlugin, int iParams)
648{
649 char sAuthId[FIELD_AUTHID_MAXLENGTH];
650 int iReturn = GetNativeString(NATIVE_GETBANINFO_OFF_STR_AUTHID, sAuthId, sizeof(sAuthId));
651
652 if (iReturn != SP_ERROR_NONE || strlen(sAuthId) < NATIVE_MIN_AUTHID_LENGTH)
653 {
654 ThrowNativeError(SP_ERROR_NATIVE, "Invalid Authid");
655 }
656
657 if (IsAuthIdConnected(sAuthId))
658 {
659 ThrowNativeError(SP_ERROR_NATIVE, "AuthID currently connected.");
660 }
661 else
662 {
663 ProcessIsBannedOffline(CALLER_NATIVE, sAuthId);
664 }
665
666 return SP_ERROR_NONE;
667}
668
669public int Native_CTBan_Client(Handle hPlugin, int iParams)
670{
671 int iClient = GetNativeCell(NATIVE_CTBAN_CELL_CLIENT);
672
673 if (iClient <= ZERO || iClient > MaxClients || !IsClientInGame(iClient))
674 {
675 ThrowNativeError(SP_ERROR_NATIVE, "Client (%d) is invalid!", iClient);
676 }
677
678 int iMinutes = GetNativeCell(NATIVE_CTBAN_CELL_TIME);
679
680 if (iMinutes < ZERO)
681 {
682 ThrowNativeError(SP_ERROR_NATIVE, "Invalid time specified (%d).", iMinutes);
683 }
684
685 int iAdmin = GetNativeCell(NATIVE_CTBAN_CELL_ADMIN);
686
687 if (iAdmin < ZERO || iAdmin > MaxClients || (iAdmin && !IsClientInGame(iAdmin)))
688 {
689 ThrowNativeError(SP_ERROR_NATIVE, "Admin (%d) is invalid!", iAdmin);
690 }
691
692 char sReason[FIELD_REASON_MAXLENGTH];
693 int iReturn = GetNativeString(NATIVE_CTBAN_STR_REASON, sReason, sizeof(sReason));
694
695 if (iReturn != SP_ERROR_NONE)
696 {
697 ThrowNativeError(SP_ERROR_NATIVE, "Invalid reason string");
698 }
699
700 if (!GetCTBanStatus(iClient))
701 {
702 PerformCTBan(iClient, iAdmin, iMinutes, _, sReason);
703 }
704 else
705 {
706 ThrowNativeError(SP_ERROR_NATIVE, g_sChatBanner, "Already CT Banned", iClient);
707 }
708
709 return SP_ERROR_NONE;
710}
711
712public int Native_CTBan_Client_Offline(Handle hPlugin, int iParams)
713{
714 if (!g_bAuthIdNativeExists)
715 {
716 ThrowNativeError(SP_ERROR_NATIVE, g_sChatBanner, "Feature Not Available");
717 }
718
719 char sAuthId[FIELD_AUTHID_MAXLENGTH];
720 int iReturn = GetNativeString(NATIVE_CTBAN_OFF_STR_AUTHID, sAuthId, sizeof(sAuthId));
721
722 if (iReturn != SP_ERROR_NONE || strlen(sAuthId) < NATIVE_MIN_AUTHID_LENGTH)
723 {
724 ThrowNativeError(SP_ERROR_NATIVE, "Invalid Authid");
725 }
726
727 if (IsAuthIdConnected(sAuthId))
728 {
729 ThrowNativeError(SP_ERROR_NATIVE, "AuthID currently connected.");
730 }
731 else
732 {
733 PerformOfflineCTBan(sAuthId, CALLER_NATIVE);
734 }
735
736 return SP_ERROR_NONE;
737}
738
739public int Native_CTBan_ChangeBanLength(Handle hPlugin, int iParams)
740{
741 int iClient = GetNativeCell(NATIVE_CHANGE_TIME_CELL_CLIENT);
742
743 if (iClient <= ZERO || iClient > MaxClients || !IsClientInGame(iClient))
744 {
745 ThrowNativeError(SP_ERROR_NATIVE, "Client (%d) is invalid!", iClient);
746 }
747
748 int iMinutes = GetNativeCell(NATIVE_CHANGE_TIME_CELL_TIME);
749
750 if (iMinutes < ZERO)
751 {
752 ThrowNativeError(SP_ERROR_NATIVE, "Invalid time specified (%d).", iMinutes);
753 }
754
755 int iAdmin = GetNativeCell(NATIVE_CHANGE_TIME_CELL_ADMIN);
756
757 if (iAdmin < ZERO || iAdmin > MaxClients || (iAdmin && !IsClientInGame(iAdmin)))
758 {
759 ThrowNativeError(SP_ERROR_NATIVE, "Admin (%d) is invalid!", iAdmin);
760 }
761
762 if (GetCTBanStatus(iClient))
763 {
764 // check if time is not changing
765 if (gA_LocalTimeRemaining[iClient] == iMinutes || (gA_LocalTimeRemaining[iClient] <= CTBAN_PERM_BAN_LENGTH && iMinutes == CTBAN_PERM_BAN_LENGTH))
766 {
767 ThrowNativeError(SP_ERROR_NATIVE, g_sChatBanner, "Invalid Amount");
768 }
769 else
770 {
771 PerformChangeCTBanTime(iClient, iAdmin, iMinutes);
772 }
773 }
774 else
775 {
776 ThrowNativeError(SP_ERROR_NATIVE, g_sChatBanner, "Not CT Banned", iClient);
777 }
778
779 return SP_ERROR_NONE;
780}
781
782public int Native_CTBan_UnbanClient(Handle hPlugin, int iParams)
783{
784 int iClient = GetNativeCell(NATIVE_UNBAN_CELL_CLIENT);
785
786 if (iClient <= ZERO || iClient > MaxClients || !IsClientInGame(iClient))
787 {
788 ThrowNativeError(SP_ERROR_NATIVE, "Client (%d) is invalid!", iClient);
789 }
790
791 int iAdmin = GetNativeCell(NATIVE_UNBAN_CELL_ADMIN);
792
793 if (iAdmin < ZERO || iAdmin > MaxClients || (iAdmin && !IsClientInGame(iAdmin)))
794 {
795 ThrowNativeError(SP_ERROR_NATIVE, "Admin (%d) is invalid!", iAdmin);
796 }
797
798 if (GetCTBanStatus(iClient))
799 {
800 // check if the cookies are ready
801 if (AreClientCookiesCached(iClient))
802 {
803 Remove_CTBan(iAdmin, iClient);
804 }
805 else
806 {
807 ThrowNativeError(SP_ERROR_NATIVE, g_sChatBanner, "Cookie Status Unavailable");
808 }
809 }
810 else
811 {
812 ThrowNativeError(SP_ERROR_NATIVE, g_sChatBanner, "Not CT Banned", iClient);
813 }
814
815 return SP_ERROR_NONE;
816}
817
818public int Native_CTBan_UnbanClient_Offline(Handle hPlugin, int iParams)
819{
820 if (!g_bAuthIdNativeExists)
821 {
822 ThrowNativeError(SP_ERROR_NATIVE, g_sChatBanner, "Feature Not Available");
823 }
824
825 char sAuthId[FIELD_AUTHID_MAXLENGTH];
826 int iReturn = GetNativeString(NATIVE_UNBAN_OFF_STR_AUTHID, sAuthId, sizeof(sAuthId));
827
828 if (iReturn != SP_ERROR_NONE || strlen(sAuthId) < NATIVE_MIN_AUTHID_LENGTH)
829 {
830 ThrowNativeError(SP_ERROR_NATIVE, "Invalid Authid");
831 }
832
833 if (IsAuthIdConnected(sAuthId))
834 {
835 ThrowNativeError(SP_ERROR_NATIVE, "AuthID currently connected.");
836 }
837 else
838 {
839 PerformOfflineUnCTBan(sAuthId, CALLER_NATIVE);
840 }
841
842 return SP_ERROR_NONE;
843}
844
845public int Native_CTBan_ForceCT(Handle hPlugin, int iParams)
846{
847 int iClient = GetNativeCell(NATIVE_FORCECT_CELL_CLIENT);
848
849 if (iClient <= ZERO || iClient > MaxClients || !IsClientInGame(iClient))
850 {
851 ThrowNativeError(SP_ERROR_NATIVE, "Client (%d) is invalid!", iClient);
852 }
853
854 int iAdmin = GetNativeCell(NATIVE_FORCECT_CELL_ADMIN);
855
856 if (iAdmin < ZERO || iAdmin > MaxClients || (iAdmin && !IsClientInGame(iAdmin)))
857 {
858 ThrowNativeError(SP_ERROR_NATIVE, "Admin (%d) is invalid!", iAdmin);
859 }
860
861 if (GetClientTeam(iClient) == CS_TEAM_CT)
862 {
863 ThrowNativeError(SP_ERROR_NATIVE, g_sChatBanner, "Unable to target");
864 }
865 else
866 {
867 ForceCTActions(iAdmin, iClient);
868 }
869
870 return SP_ERROR_NONE;
871}
872
873public int Native_CTBan_UnForceCT(Handle hPlugin, int iParams)
874{
875 int iClient = GetNativeCell(NATIVE_UNFORCECT_CELL_CLIENT);
876
877 if (iClient <= ZERO || iClient > MaxClients || !IsClientInGame(iClient))
878 {
879 ThrowNativeError(SP_ERROR_NATIVE, "Client (%d) is invalid!", iClient);
880 }
881
882 int iAdmin = GetNativeCell(NATIVE_UNFORCECT_CELL_ADMIN);
883
884 if (iAdmin < ZERO || iAdmin > MaxClients || (iAdmin && !IsClientInGame(iAdmin)))
885 {
886 ThrowNativeError(SP_ERROR_NATIVE, "Admin (%d) is invalid!", iAdmin);
887 }
888
889 UnForceCTActions(iAdmin, iClient, true);
890
891 return SP_ERROR_NONE;
892}
893
894public void OnAllPluginsLoaded()
895{
896 g_bAuthIdNativeExists = IsSetAuthIdNativePresent();
897}
898
899public Action Event_PlayerSpawn(Event hEvent, const char[] sName, bool bDontBroadcast)
900{
901 int iClient = GetClientOfUserId(GetEventInt(hEvent, "userid"));
902
903 if (IsClientInGame(iClient) && GetClientTeam(iClient) == CS_TEAM_CT)
904 {
905 if (!g_bA_Temp_CTBan_Override[iClient] && GetCTBanStatus(iClient))
906 {
907 #if defined CTBAN_DEBUG
908 LogMessage("%N spawned as CT but was CTBanned. Moving to Terrorist team.", iClient);
909 #endif
910
911 EnforceCTBan(iClient);
912 }
913 }
914
915 return Plugin_Continue;
916}
917
918public Action Event_PlayerTeam(Event hEvent, const char[] sName, bool bDontBroadcast)
919{
920 int iUserID = GetEventInt(hEvent, "userid");
921 int iClient = GetClientOfUserId(iUserID);
922 int iTeam = GetEventInt(hEvent, "team");
923 bool bDisconnected = GetEventBool(hEvent, "disconnect");
924
925 if (bDisconnected || !iClient || !IsClientInGame(iClient))
926 {
927 return Plugin_Continue;
928 }
929
930 if (iTeam == CS_TEAM_CT && GetCTBanStatus(iClient))
931 {
932 // if a CT banned player is on CT and did not get an override they will be swapped after they spawn
933 // BUT an admin likely did this and should get instruction to use !forcect
934 if (!g_bA_Temp_CTBan_Override[iClient])
935 {
936 // only admins need the message
937 for (int iIndex = ONE; iIndex <= MaxClients; iIndex++)
938 {
939 if (IsClientInGame(iIndex) && CheckCommandAccess(iIndex, "sm_chat", ADMFLAG_CHAT))
940 {
941 CPrintToChat(iIndex, g_sChatBanner, "CTBanned Player On CT Team", iClient);
942 }
943 }
944 }
945
946 // if they are still alive then we should not even wait until the respawn
947 if (IsPlayerAlive(iClient))
948 {
949 CreateTimer(DELAY_ENFORCEMENT_TIME, Timer_DelayEnforcement, iUserID, TIMER_FLAG_NO_MAPCHANGE);
950 }
951 }
952
953 return Plugin_Continue;
954}
955
956public Action Timer_DelayEnforcement(Handle hTimer, any iUserID)
957{
958 int iClient = GetClientOfUserId(iUserID);
959
960 if (iClient && IsClientInGame(iClient) && GetClientTeam(iClient) == CS_TEAM_CT && GetCTBanStatus(iClient))
961 {
962 EnforceCTBan(iClient);
963 }
964}
965
966public Action Event_JoinTeamFailed(Handle hEvent, const char[] sName, bool bDontBroadcast)
967{
968 int iClient = GetClientOfUserId(GetEventInt(hEvent, "userid"));
969 if (iClient && IsClientInGame(iClient))
970 {
971 int iReason = GetEventInt(hEvent, "reason");
972
973 if (iReason == JOINFAILREASON_ONECHANGE)
974 {
975 // Check if client is banned and is blocked
976 if (GetCTBanStatus(iClient))
977 {
978 #if defined CTBAN_DEBUG
979 LogMessage("%N was unable to join a team due to limit. Forcing to Terrorist team.");
980 #endif
981
982 ChangeClientTeam(iClient, CS_TEAM_T);
983
984 return Plugin_Handled;
985 }
986 }
987 }
988
989 return Plugin_Continue;
990}
991
992// consider if someone does a 'retry' and clientprefs is accessinsg on its ClientConnectCallback and this is also trying to set a value
993public void OnClientAuthorized(int iClient, const char[] sAuthID)
994{
995 // check if the Steam ID is in the Rage Ban list
996 int iNeedle = FindStringInArray(gA_DSteamIDs, sAuthID);
997 if (iNeedle != VALUE_NOT_FOUND_IN_ARRAY)
998 {
999 g_bRageBanArrayChanged = true;
1000
1001 RemoveFromArray(gA_DNames, iNeedle);
1002 RemoveFromArray(gA_DSteamIDs, iNeedle);
1003 #if defined CTBAN_DEBUG
1004 LogMessage("removed %N from Rage Bannable player list for re-connecting to the server", iClient);
1005 #endif
1006 }
1007
1008 // check if we have a database connection
1009 if (gH_BanDatabase != INVALID_HANDLE)
1010 {
1011 // check if the Steam ID is in the Timed Ban list
1012 char sQuery[QUERY_MAXLENGTH];
1013 Format(sQuery, sizeof(sQuery), CTBAN_QUERY_TIME_SELECT_BANTIME, g_sTimesTableName, sAuthID);
1014 SQL_TQuery(gH_BanDatabase, DB_Callback_OnClientAuthed, sQuery, view_as<int>(iClient));
1015 }
1016 else
1017 {
1018 CreateTimer(AUTH_RESCAN_TIME, Timer_OnAuthCheckDatabase, iClient, TIMER_FLAG_NO_MAPCHANGE);
1019 }
1020}
1021
1022public Action Timer_OnAuthCheckDatabase(Handle hTimer, any iClient)
1023{
1024 if (gH_BanDatabase != INVALID_HANDLE && IsClientInGame(iClient))
1025 {
1026 char sAuthID[FIELD_AUTHID_MAXLENGTH];
1027 GetClientAuthId(iClient, AuthId_Steam2, sAuthID, sizeof(sAuthID));
1028
1029 char sQuery[QUERY_MAXLENGTH];
1030 Format(sQuery, sizeof(sQuery), CTBAN_QUERY_TIME_SELECT_BANTIME, g_sTimesTableName, sAuthID);
1031 SQL_TQuery(gH_BanDatabase, DB_Callback_OnClientAuthed, sQuery, view_as<int>(iClient));
1032 }
1033 else if(IsClientInGame(iClient))
1034 {
1035 CreateTimer(AUTH_RESCAN_TIME, Timer_OnAuthCheckDatabase, iClient, TIMER_FLAG_NO_MAPCHANGE);
1036 }
1037}
1038
1039public void DB_Callback_OnClientAuthed(Handle hOwner, Handle hCallback, const char[] sError, any iClient)
1040{
1041 if (hCallback == INVALID_HANDLE)
1042 {
1043 LogError("Error in OnClientAuthorized query: %s", sError);
1044 }
1045 else
1046 {
1047 int iRowCount = SQL_GetRowCount(hCallback);
1048 #if defined CTBAN_DEBUG
1049 LogMessage("SQL Auth: %d row count", iRowCount);
1050 #endif
1051 if (iRowCount)
1052 {
1053 SQL_FetchRow(hCallback);
1054 int iBanTimeRemaining = SQL_FetchInt(hCallback, CLIENT_AUTHED_CB_FIELD_TIMELEFT);
1055 #if defined CTBAN_DEBUG
1056 LogMessage("SQL Auth: %N joined with %i time remaining on ban", iClient, iBanTimeRemaining);
1057 #endif
1058 // update local time
1059 PushArrayCell(gA_TimedBanLocalList, iClient);
1060 gA_LocalTimeRemaining[iClient] = iBanTimeRemaining;
1061 }
1062 }
1063}
1064
1065public void AdminMenu_RageBan(Handle hTopMenu, TopMenuAction eAction, TopMenuObject eObjectID, int iClient, char[] sBuffer, int iMaxLength)
1066{
1067 if (eAction == TopMenuAction_DisplayOption)
1068 {
1069 Format(sBuffer, iMaxLength, "%T", "Rage Ban Admin Menu", iClient);
1070 }
1071 else if (eAction == TopMenuAction_SelectOption)
1072 {
1073 DisplayRageBanMenu(iClient, GetArraySize(gA_DNames));
1074 }
1075}
1076
1077void DisplayRageBanMenu(int iClient, int iArraySize)
1078{
1079 if (iArraySize == ZERO)
1080 {
1081 CPrintToChat(iClient, g_sChatBanner, "No Targets");
1082 }
1083 else
1084 {
1085 Handle hMenu = CreateMenu(MenuHandler_RageBan);
1086
1087 SetMenuTitle(hMenu, "%T", "Rage Ban Menu Title", iClient);
1088 SetMenuExitBackButton(hMenu, true);
1089
1090 for (int iArrayIndex = ZERO; iArrayIndex < iArraySize; iArrayIndex++)
1091 {
1092 char sName[FIELD_NAME_MAXLENGTH];
1093 GetArrayString(gA_DNames, iArrayIndex, sName, sizeof(sName));
1094
1095 char sAuthID[FIELD_AUTHID_MAXLENGTH];
1096 GetArrayString(gA_DSteamIDs, iArrayIndex, sAuthID, sizeof(sAuthID));
1097
1098 AddMenuItem(hMenu, sAuthID, sName);
1099 }
1100
1101 DisplayMenu(hMenu, iClient, MENU_TIME_FOREVER);
1102 }
1103}
1104
1105public int MenuHandler_RageBan(Handle hMenu, MenuAction action, int iClient, int iMenuChoice)
1106{
1107 if (action == MenuAction_End)
1108 {
1109 CloseHandle(hMenu);
1110 }
1111 else if (action == MenuAction_Cancel)
1112 {
1113 if ((iMenuChoice == MenuCancel_ExitBack) && (gH_TopMenu != INVALID_HANDLE))
1114 {
1115 DisplayTopMenu(gH_TopMenu, iClient, TopMenuPosition_LastCategory);
1116 }
1117 }
1118 else if (action == MenuAction_Select)
1119 {
1120 if (!g_bAuthIdNativeExists)
1121 {
1122 ReplyToCommand(iClient, g_sChatBanner, "Feature Not Available");
1123 }
1124 else
1125 {
1126 char sAuthID[FIELD_AUTHID_MAXLENGTH];
1127 char sTargetName[MAX_TARGET_LENGTH];
1128 GetMenuItem(hMenu, iMenuChoice, sAuthID, sizeof(sAuthID), _, sTargetName, sizeof(sTargetName));
1129
1130 #if defined CTBAN_DEBUG
1131 CPrintToChat(iClient, g_sChatBanner, "Ready to CT Ban", sAuthID);
1132 #endif
1133
1134 SetAuthIdCookie(sAuthID, g_CT_Cookie, COOKIE_BANNED_STRING);
1135
1136 char sAdminSteamID[FIELD_AUTHID_MAXLENGTH];
1137 GetClientAuthId(iClient, AuthId_Steam2, sAdminSteamID, sizeof(sAdminSteamID));
1138
1139 LogMessage("%N (%s) has issued a rage ban on %s (%s) indefinitely.", iClient, sAdminSteamID, sTargetName, sAuthID);
1140
1141 ShowActivity2(iClient, "", g_sChatBanner, "Rage Ban", sTargetName);
1142
1143 int iTimeStamp = GetTime();
1144 char sTempName[FIELD_NAME_MAXLENGTH];
1145 char sQuery[QUERY_MAXLENGTH];
1146 char sEscapedPerpName[MAX_SAFE_ESCAPE_QUERY(FIELD_NAME_MAXLENGTH)];
1147 char sEscapedAdminName[MAX_SAFE_ESCAPE_QUERY(FIELD_NAME_MAXLENGTH)];
1148 Format(sTempName, sizeof(sTempName), "%s", sTargetName);
1149 SQL_EscapeString(gH_BanDatabase, sTempName, sEscapedPerpName, sizeof(sEscapedPerpName));
1150 Format(sTempName, sizeof(sTempName), "%N", iClient);
1151 SQL_EscapeString(gH_BanDatabase, sTempName, sEscapedAdminName, sizeof(sEscapedAdminName));
1152
1153 Format(sQuery, sizeof(sQuery), CTBAN_QUERY_LOG_INSERT, g_sLogTableName, iTimeStamp, sAuthID, sEscapedPerpName, sAdminSteamID, sEscapedAdminName, CTBAN_PERM_BAN_LENGTH, CTBAN_PERM_BAN_LENGTH, RAGEBAN_LOG_REASON);
1154
1155 #if defined CTBAN_DEBUG
1156 LogMessage("log query: %s", sQuery);
1157 #endif
1158
1159 SQL_TQuery(gH_BanDatabase, DB_Callback_CTBan, sQuery, iClient);
1160
1161 // Remove any existing time information to make the CTBan permanently
1162 Format(sQuery, sizeof(sQuery), CTBAN_QUERY_TIME_DELETE, g_sTimesTableName, sAuthID);
1163 SQL_TQuery(gH_BanDatabase, DB_Callback_DisconnectAction, sQuery);
1164 }
1165 }
1166}
1167
1168public void CP_Callback_ResetAllCTBans(Handle hOwner, Handle hCallback, const char[] sError, any data)
1169{
1170 if (hCallback == INVALID_HANDLE)
1171 {
1172 LogError("Error reseting the CTBan cookies: %s", sError);
1173 }
1174 else
1175 {
1176 LogMessage("CTBans Cookie Bans were successfully RESET by the administrator.");
1177 }
1178}
1179
1180public Action Command_Offline_CTBan(int iClient, int iArgs)
1181{
1182 if (g_bAuthIdNativeExists)
1183 {
1184 char sAuthId[FIELD_AUTHID_MAXLENGTH];
1185 GetCmdArgString(sAuthId, sizeof(sAuthId));
1186
1187 if (IsAuthIdConnected(sAuthId))
1188 {
1189 ReplyToCommand(iClient, g_sChatBanner, "Unable to target");
1190 }
1191 else
1192 {
1193 PerformOfflineCTBan(sAuthId, iClient);
1194 }
1195 }
1196 else
1197 {
1198 ReplyToCommand(iClient, g_sChatBanner, "Feature Not Available");
1199 }
1200 return Plugin_Handled;
1201}
1202
1203void PerformOfflineCTBan(char[] sAuthId, int iAdmin)
1204{
1205 SetAuthIdCookie(sAuthId, g_CT_Cookie, COOKIE_BANNED_STRING);
1206
1207 char sAdminSteamID[FIELD_AUTHID_MAXLENGTH];
1208 if (iAdmin > ZERO)
1209 {
1210 GetClientAuthId(iAdmin, AuthId_Steam2, sAdminSteamID, sizeof(sAdminSteamID));
1211 }
1212 else
1213 {
1214 sAdminSteamID = CONSOLE_AUTHID;
1215 }
1216
1217 int iTimeStamp = GetTime();
1218 char sQuery[QUERY_MAXLENGTH];
1219 char sTempName[FIELD_NAME_MAXLENGTH];
1220 char sEscapedPerpAuthId[MAX_SAFE_ESCAPE_QUERY(FIELD_NAME_MAXLENGTH)];
1221 SQL_EscapeString(gH_BanDatabase, sAuthId, sEscapedPerpAuthId, sizeof(sEscapedPerpAuthId));
1222
1223 char sEscapedAdminName[MAX_SAFE_ESCAPE_QUERY(FIELD_NAME_MAXLENGTH)];
1224 if (iAdmin > ZERO)
1225 {
1226 Format(sTempName, sizeof(sTempName), "%N", iAdmin);
1227 SQL_EscapeString(gH_BanDatabase, sTempName, sEscapedAdminName, sizeof(sEscapedAdminName));
1228 }
1229 else
1230 {
1231 sEscapedAdminName = CONSOLE_USER_NAME;
1232 }
1233
1234 Format(sQuery, sizeof(sQuery), CTBAN_QUERY_LOG_INSERT, g_sLogTableName, iTimeStamp, sEscapedPerpAuthId, OFFLINE_NAME_UNAVAILBLE, sAdminSteamID, sEscapedAdminName, CTBAN_PERM_BAN_LENGTH, CTBAN_PERM_BAN_LENGTH, REASON_OFFLINECTBAN);
1235
1236 #if defined CTBAN_DEBUG
1237 LogMessage("log query: %s", sQuery);
1238 #endif
1239
1240 SQL_TQuery(gH_BanDatabase, DB_Callback_CTBan, sQuery, iAdmin);
1241
1242 if (iAdmin == CALLER_NATIVE)
1243 {
1244 // No response
1245 }
1246 {
1247 ReplyToCommand(iAdmin, g_sChatBanner, "Banned AuthId", sAuthId);
1248 }
1249
1250 Call_StartForward(g_hFrwd_OnCTBan_Offline);
1251 Call_PushString(sAuthId);
1252 Call_PushCell(iAdmin);
1253 Call_Finish();
1254}
1255
1256public Action Command_ForceCT(int iClient, int iArgs)
1257{
1258 if (!iClient && !iArgs)
1259 {
1260 ReplyToCommand(iClient, g_sChatBanner, "Command Usage", "sm_forcect <player>");
1261 return Plugin_Handled;
1262 }
1263
1264 if (!iArgs)
1265 {
1266 DisplayCTBannedPlayerMenu(iClient, e_ForceCT);
1267 return Plugin_Handled;
1268 }
1269
1270 char sTarget[MAX_TARGET_LENGTH];
1271 GetCmdArg(FORCECT_ARG_TARGET, sTarget, sizeof(sTarget));
1272
1273 char sClientName[MAX_TARGET_LENGTH];
1274 int aiTargetList[MAXPLAYERS];
1275 int iTargetCount;
1276 bool b_tn_is_ml;
1277 iTargetCount = ProcessTargetString(sTarget, iClient, aiTargetList, MAXPLAYERS, COMMAND_FILTER_NO_MULTI, sClientName, sizeof(sClientName), b_tn_is_ml);
1278
1279 if (iTargetCount < ONE)
1280 {
1281 ReplyToTargetError(iClient, iTargetCount);
1282 }
1283 else
1284 {
1285 int iTarget = aiTargetList[ZERO];
1286
1287 if (iTarget && IsClientInGame(iTarget))
1288 {
1289 if (GetClientTeam(iTarget) == CS_TEAM_CT)
1290 {
1291 ReplyToCommand(iClient, g_sChatBanner, "Unable to target");
1292 }
1293 else
1294 {
1295 ForceCTActions(iClient, iTarget);
1296 }
1297 }
1298 }
1299 return Plugin_Handled;
1300}
1301
1302void ForceCTActions(int iAdmin, int iTarget)
1303{
1304 if (IsClientInGame(iTarget))
1305 {
1306 g_bA_Temp_CTBan_Override[iTarget] = true;
1307
1308 if (IsPlayerAlive(iTarget))
1309 {
1310 StripAllWeapons(iTarget);
1311 ForcePlayerSuicide(iTarget);
1312 }
1313
1314 ChangeClientTeam(iTarget, CS_TEAM_CT);
1315
1316 if (GetConVarBool(gH_Cvar_Respawn))
1317 {
1318 CS_RespawnPlayer(iTarget);
1319 }
1320
1321 ShowActivity2(iAdmin, "", g_sChatBanner, "Force CT", iTarget);
1322
1323 Call_StartForward(g_hFrwd_OnForceCT);
1324 Call_PushCell(iTarget);
1325 Call_PushCell(iAdmin);
1326 Call_Finish();
1327 }
1328}
1329
1330public Action Command_UnForceCT(int iClient, int iArgs)
1331{
1332 if (!iClient && !iArgs)
1333 {
1334 ReplyToCommand(iClient, g_sChatBanner, "Command Usage", "sm_unforcect <player>");
1335 return Plugin_Handled;
1336 }
1337
1338 if (!iArgs)
1339 {
1340 DisplayUnForceCTPlayerMenu(iClient);
1341 return Plugin_Handled;
1342 }
1343
1344 char sTarget[MAX_TARGET_LENGTH];
1345 GetCmdArg(UNFORCECT_ARG_TARGET, sTarget, sizeof(sTarget));
1346
1347 char sClientName[MAX_TARGET_LENGTH];
1348 int aiTargetLlist[MAXPLAYERS];
1349 int iTargetCount;
1350 bool b_tn_is_ml;
1351 iTargetCount = ProcessTargetString(sTarget, iClient, aiTargetLlist, MAXPLAYERS, COMMAND_FILTER_NO_MULTI, sClientName, sizeof(sClientName), b_tn_is_ml);
1352
1353 if (iTargetCount < ONE)
1354 {
1355 ReplyToTargetError(iClient, iTargetCount);
1356 }
1357 else
1358 {
1359 int iTarget = aiTargetLlist[ZERO];
1360 UnForceCTActions(iClient, iTarget);
1361 }
1362 return Plugin_Handled;
1363}
1364
1365void UnForceCTActions(int iAdmin, int iTarget, bool bQuiet = false)
1366{
1367 if (!g_bA_Temp_CTBan_Override[iTarget])
1368 {
1369 if (!bQuiet)
1370 {
1371 ReplyToCommand(iAdmin, g_sChatBanner, "Unable to target");
1372 }
1373 }
1374 else
1375 {
1376 if (IsClientInGame(iTarget))
1377 {
1378 if (GetClientTeam(iTarget) == CS_TEAM_CT)
1379 {
1380 if (IsPlayerAlive(iTarget))
1381 {
1382 StripAllWeapons(iTarget);
1383 ForcePlayerSuicide(iTarget);
1384 }
1385
1386 ChangeClientTeam(iTarget, CS_TEAM_T);
1387
1388 if (GetConVarBool(gH_Cvar_Respawn))
1389 {
1390 CS_RespawnPlayer(iTarget);
1391 }
1392 }
1393 g_bA_Temp_CTBan_Override[iTarget] = false;
1394
1395 if (!bQuiet)
1396 {
1397 ShowActivity2(iAdmin, "", g_sChatBanner, "Unforce CT", iTarget);
1398 }
1399
1400 Call_StartForward(g_hFrwd_OnUnforceCT);
1401 Call_PushCell(iTarget);
1402 Call_PushCell(iAdmin);
1403 Call_Finish();
1404 }
1405 }
1406}
1407
1408void DisplayUnForceCTPlayerMenu(int iClient)
1409{
1410 Handle hMenu = CreateMenu(MenuHandler_UnForceCT);
1411
1412 SetMenuTitle(hMenu, "%T", "UnForce CT Menu Title", iClient);
1413 SetMenuExitBackButton(hMenu, true);
1414
1415 int iCount = ZERO;
1416 char sUserId[MAX_USERID_LENGTH];
1417 char sName[MAX_NAME_LENGTH];
1418
1419 // filter away those with current overrides
1420 for (int iIndex = ONE; iIndex <= MaxClients; iIndex++)
1421 {
1422 if (IsClientInGame(iIndex))
1423 {
1424 if (g_bA_Temp_CTBan_Override[iIndex])
1425 {
1426 IntToString(GetClientUserId(iIndex), sUserId, sizeof(sUserId));
1427 GetClientName(iIndex, sName, sizeof(sName));
1428
1429 AddMenuItem(hMenu, sUserId, sName);
1430
1431 iCount++;
1432 }
1433 }
1434 }
1435
1436 if (!iCount)
1437 {
1438 CPrintToChat(iClient, g_sChatBanner, "No matching clients");
1439 }
1440
1441 DisplayMenu(hMenu, iClient, MENU_TIME_FOREVER);
1442}
1443
1444public Action Command_ResetCookies(int iClient, int iArgs)
1445{
1446 char sArgs[MAX_RESET_ARG_LENGTH];
1447 GetCmdArgString(sArgs, sizeof(sArgs));
1448
1449 if (StrEqual("force", sArgs))
1450 {
1451 if (!g_iCookieIndex)
1452 {
1453 ReplyToCommand(iClient, g_sChatBanner, "Cookie not Found", "Banned_From_CT");
1454 }
1455 else
1456 {
1457 char sQuery[QUERY_MAXLENGTH];
1458 Format(sQuery, sizeof(sQuery), CTBAN_QUERY_CP_RESET_COOKIES, g_iCookieIndex);
1459
1460 #if defined CTBAN_DEBUG
1461 LogMessage("Query to run: %s", sQuery);
1462 #endif
1463
1464 SQL_TQuery(gH_CP_DataBase, CP_Callback_ResetAllCTBans, sQuery);
1465
1466 ShowActivity2(iClient, "", g_sChatBanner, "Reset Cookies");
1467 }
1468 }
1469 else
1470 {
1471 ReplyToCommand(iClient, g_sChatBanner, "Reset Cookie Confirmation");
1472 }
1473
1474 return Plugin_Handled;
1475}
1476
1477public Action Command_Offline_UnCTBan(int iClient, int iArgs)
1478{
1479 if (g_bAuthIdNativeExists)
1480 {
1481 char sAuthId[FIELD_AUTHID_MAXLENGTH];
1482 GetCmdArgString(sAuthId, sizeof(sAuthId));
1483
1484 if (IsAuthIdConnected(sAuthId))
1485 {
1486 ReplyToCommand(iClient, g_sChatBanner, "Unable to target");
1487 }
1488 else
1489 {
1490 PerformOfflineUnCTBan(sAuthId, iClient);
1491 }
1492 }
1493 else
1494 {
1495 ReplyToCommand(iClient, g_sChatBanner, "Feature Not Available");
1496 }
1497
1498 return Plugin_Handled;
1499}
1500
1501void PerformOfflineUnCTBan(char[] sAuthId, int iAdmin)
1502{
1503 SetAuthIdCookie(sAuthId, g_CT_Cookie, COOKIE_UNBANNED_STRING);
1504
1505 char sEscapedAuthId[MAX_SAFE_ESCAPE_QUERY(FIELD_NAME_MAXLENGTH)];
1506 SQL_EscapeString(gH_BanDatabase, sAuthId, sEscapedAuthId, sizeof(sEscapedAuthId));
1507
1508 char sQuery[QUERY_MAXLENGTH];
1509 Format(sQuery, sizeof(sQuery), CTBAN_QUERY_LOG_EXPIRE, g_sLogTableName, sEscapedAuthId);
1510
1511 #if defined CTBAN_DEBUG
1512 LogMessage("log query: %s", sQuery);
1513 #endif
1514
1515 SQL_TQuery(gH_BanDatabase, DB_Callback_RemoveCTBan, sQuery, CALLER_DO_NOT_REPLY);
1516
1517 // delete from the timedban database if there was one
1518 Format(sQuery, sizeof(sQuery), CTBAN_QUERY_TIME_DELETE, g_sTimesTableName, sEscapedAuthId);
1519
1520 #if defined CTBAN_DEBUG
1521 LogMessage("log query: %s", sQuery);
1522 #endif
1523
1524 SQL_TQuery(gH_BanDatabase, DB_Callback_RemoveCTBan, sQuery, CALLER_DO_NOT_REPLY);
1525
1526 if (iAdmin == CALLER_NATIVE)
1527 {
1528 // No response
1529 }
1530 else
1531 {
1532 ReplyToCommand(iAdmin, g_sChatBanner, "Unbanned AuthId", sAuthId);
1533
1534 LogMessage("%N has removed the CT ban on %s.", iAdmin, sAuthId);
1535 }
1536
1537 Call_StartForward(g_hFrwd_OnUnCTBan_Offline);
1538 Call_PushString(sAuthId);
1539 Call_PushCell(iAdmin);
1540 Call_Finish();
1541}
1542
1543public Action Command_RageBan(int iClient, int iArgs)
1544{
1545 int iArraySize = GetArraySize(gA_DNames);
1546 if (iArraySize == ZERO)
1547 {
1548 ReplyToCommand(iClient, g_sChatBanner, "No Targets");
1549 return Plugin_Handled;
1550 }
1551
1552 if (!iArgs)
1553 {
1554 if (iClient)
1555 {
1556 DisplayRageBanMenu(iClient, iArraySize);
1557 }
1558 // Console user
1559 else
1560 {
1561 PrintToServer(g_sChatBanner, "Rage Ban Menu Title");
1562
1563 for (int iArrayIndex = ZERO; iArrayIndex < iArraySize; iArrayIndex++)
1564 {
1565 char sName[FIELD_NAME_MAXLENGTH];
1566 GetArrayString(gA_DNames, iArrayIndex, sName, sizeof(sName));
1567
1568 char sAuthID[FIELD_AUTHID_MAXLENGTH];
1569 GetArrayString(gA_DSteamIDs, iArrayIndex, sAuthID, sizeof(sAuthID));
1570
1571 PrintToServer("[CTBAN] (%d.) %s [%s]", iArrayIndex + ONE, sName, sAuthID);
1572 }
1573
1574 g_bRageBanArrayChanged = false;
1575 }
1576 return Plugin_Handled;
1577 }
1578 else
1579 {
1580 if (iClient)
1581 {
1582 ReplyToCommand(iClient, g_sChatBanner, "Command Usage", RAGEBAN_COMMAND);
1583 }
1584 // Console user
1585 else
1586 {
1587 char sTarget[MAX_MENU_INT_CHOICE_LENGTH];
1588 GetCmdArg(RAGEBAN_ARG_CONSOLE_TARGET, sTarget, sizeof(sTarget));
1589
1590 int iArrayIndex = StringToInt(sTarget) - ONE;
1591
1592 if ((iArrayIndex >= iArraySize) || (iArrayIndex < ZERO))
1593 {
1594 ReplyToCommand(iClient, g_sChatBanner, "No matching client");
1595 }
1596 else if (g_bRageBanArrayChanged)
1597 {
1598 ReplyToCommand(iClient, g_sChatBanner, "Player no longer available");
1599 }
1600 else
1601 {
1602 char sTargetName[FIELD_NAME_MAXLENGTH];
1603 GetArrayString(gA_DNames, iArrayIndex, sTargetName, sizeof(sTargetName));
1604
1605 char sAuthID[FIELD_AUTHID_MAXLENGTH];
1606 GetArrayString(gA_DSteamIDs, iArrayIndex, sAuthID, sizeof(sAuthID));
1607
1608 #if defined CTBAN_DEBUG
1609 PrintToServer(g_sChatBanner, "Ready to CT Ban", sAuthID);
1610 #endif
1611
1612 SetAuthIdCookie(sAuthID, g_CT_Cookie, COOKIE_BANNED_STRING);
1613
1614 LogMessage("%N has issued a rage ban on %s (%s) indefinitely.", iClient, sTargetName, sAuthID);
1615
1616 ShowActivity2(iClient, "", g_sChatBanner, "Rage Ban", sTargetName);
1617
1618 int iTimeStamp = GetTime();
1619 char sTempName[FIELD_NAME_MAXLENGTH];
1620 char sQuery[QUERY_MAXLENGTH];
1621 char sEscapedPerpName[MAX_SAFE_ESCAPE_QUERY(FIELD_NAME_MAXLENGTH)];
1622 Format(sTempName, sizeof(sTempName), "%s", sTargetName);
1623 SQL_EscapeString(gH_BanDatabase, sTempName, sEscapedPerpName, sizeof(sEscapedPerpName));
1624
1625 Format(sQuery, sizeof(sQuery), CTBAN_QUERY_LOG_INSERT, g_sLogTableName, iTimeStamp, sAuthID, sEscapedPerpName, CONSOLE_AUTHID, CONSOLE_USER_NAME, CTBAN_PERM_BAN_LENGTH, CTBAN_PERM_BAN_LENGTH, RAGEBAN_LOG_REASON);
1626
1627 #if defined CTBAN_DEBUG
1628 LogMessage("log query: %s", sQuery);
1629 #endif
1630
1631 SQL_TQuery(gH_BanDatabase, DB_Callback_CTBan, sQuery, iClient);
1632
1633 // Remove any existing time information to make the CTBan permanently
1634 Format(sQuery, sizeof(sQuery), CTBAN_QUERY_TIME_DELETE, g_sTimesTableName, sAuthID);
1635 SQL_TQuery(gH_BanDatabase, DB_Callback_DisconnectAction, sQuery);
1636 }
1637 }
1638 }
1639
1640 return Plugin_Handled;
1641}
1642
1643public Action Timer_CheckTimedCTBans(Handle hTimer)
1644{
1645 // check if anyone has a time
1646 int iTimeArraySize = GetArraySize(gA_TimedBanLocalList);
1647
1648 // credit for this idea goes to Kigen
1649 for (int iIndex = ZERO; iIndex < iTimeArraySize; iIndex++)
1650 {
1651 int iBannedClientIndex = GetArrayCell(gA_TimedBanLocalList, iIndex);
1652 if (IsClientInGame(iBannedClientIndex))
1653 {
1654 if (IsPlayerAlive(iBannedClientIndex))
1655 {
1656 gA_LocalTimeRemaining[iBannedClientIndex]--;
1657
1658 #if defined CTBAN_DEBUG
1659 LogMessage("found alive time banned client with %i remaining", gA_LocalTimeRemaining[iBannedClientIndex]);
1660 #endif
1661
1662 // check if we should remove the CT ban
1663 if (gA_LocalTimeRemaining[iBannedClientIndex] <= ZERO)
1664 {
1665 // remove CT ban
1666 RemoveFromArray(gA_TimedBanLocalList, iIndex);
1667 iTimeArraySize--;
1668
1669 Remove_CTBan(ZERO, iBannedClientIndex, true);
1670
1671 #if defined CTBAN_DEBUG
1672 LogMessage("removed CT ban on %N", iBannedClientIndex);
1673 #endif
1674 }
1675 }
1676 }
1677 }
1678}
1679
1680public void OnConfigsExecuted()
1681{
1682 #if defined CTBAN_DEBUG
1683 LogMessage("Connecting to clientprefs database");
1684 #endif
1685
1686 SQL_TConnect(CP_Callback_Connect, "clientprefs");
1687
1688 char sDatabaseDriver[64];
1689 GetConVarString(gH_Cvar_Database_Driver, sDatabaseDriver, sizeof(sDatabaseDriver));
1690
1691 #if defined CTBAN_DEBUG
1692 LogMessage("Connecting to log database");
1693 #endif
1694
1695 SQL_TConnect(DB_Callback_Connect, sDatabaseDriver);
1696
1697 ParseCTBanReasonsFile(gH_DArray_Reasons);
1698
1699 gH_KV_BanLengths = ParseCTBanLengthsFile(gH_KV_BanLengths);
1700}
1701
1702public void DB_Callback_Connect(Handle hOwner, Handle hCallback, const char[] sError, any data)
1703{
1704 if (hCallback == INVALID_HANDLE)
1705 {
1706 LogError("Default database database connection failure: %s", sError);
1707 SetFailState("Error while connecting to default database. Exiting.");
1708 }
1709 else
1710 {
1711 gH_BanDatabase = hCallback;
1712
1713 // Determine the type of database we're on so we may modify the syntax of queries
1714 char sDatabaseID[MAX_DATABASE_ID_LENGTH];
1715 SQL_GetDriverIdent(SQL_ReadDriver(gH_BanDatabase), sDatabaseID, sizeof(sDatabaseID));
1716 if (StrEqual(sDatabaseID, "mysql"))
1717 {
1718 g_eDatabaseType = e_MySQL;
1719 }
1720 else if (StrEqual(sDatabaseID, "sqlite"))
1721 {
1722 g_eDatabaseType = e_SQLite;
1723 }
1724 else
1725 {
1726 g_eDatabaseType = e_Unknown;
1727 }
1728
1729 // figure out table prefix situation
1730 char sPrefix[MAX_TABLE_LENGTH - MAX_DEFAULT_TABLE_LENGTH];
1731 GetConVarString(gH_Cvar_Table_Prefix, sPrefix, sizeof(sPrefix));
1732 if (strlen(sPrefix) > ZERO)
1733 {
1734 Format(g_sTimesTableName, sizeof(g_sTimesTableName), "%s_CTBan_Times", sPrefix);
1735 }
1736 else
1737 {
1738 Format(g_sTimesTableName, sizeof(g_sTimesTableName), "CTBan_Times");
1739 }
1740
1741 char sQuery[QUERY_MAXLENGTH];
1742 Format(sQuery, sizeof(sQuery), CTBAN_QUERY_TIME_CREATE, g_sTimesTableName, FIELD_AUTHID_MAXLENGTH);
1743
1744 #if defined CTBAN_DEBUG
1745 LogMessage("times table create query %s", sQuery);
1746 #endif
1747
1748 // create database if not already there
1749 SQL_TQuery(gH_BanDatabase, DB_Callback_CreateTime, sQuery);
1750
1751 if (strlen(sPrefix) > ZERO)
1752 {
1753 Format(g_sLogTableName, sizeof(g_sLogTableName), "%s_CTBan_Log", sPrefix);
1754 }
1755 else
1756 {
1757 Format(g_sLogTableName, sizeof(g_sLogTableName), "CTBan_Log");
1758 }
1759
1760 Format(sQuery, sizeof(sQuery), CTBAN_QUERY_LOG_CREATE, g_sLogTableName, FIELD_AUTHID_MAXLENGTH, FIELD_NAME_MAXLENGTH, FIELD_AUTHID_MAXLENGTH, FIELD_NAME_MAXLENGTH, FIELD_REASON_MAXLENGTH);
1761
1762 #if defined CTBAN_DEBUG
1763 LogMessage("log table create query %s", sQuery);
1764 #endif
1765
1766 SQL_TQuery(gH_BanDatabase, DB_Callback_CreateLog, sQuery);
1767 }
1768}
1769
1770public void DB_Callback_CheckTableVersion(Handle hOwner, Handle hCallback, const char[] sError, any data)
1771{
1772 if (hCallback == INVALID_HANDLE)
1773 {
1774 #if defined CTBAN_DEBUG
1775 LogMessage("Table layout check revealed this error: %s", sError);
1776 #endif
1777
1778 // Check specifically for if there was a problem finding the ban_id column
1779 if (StrContains(sError, "column", false) != SUBSTRING_NOT_FOUND)
1780 {
1781 LogMessage("Upgrading CTBan_Log Table to Version Two...");
1782
1783 char sQuery[QUERY_MAXLENGTH];
1784 Format(sQuery, sizeof(sQuery), CTBAN_QUERY_LOG_TO_V2_DROPKEY, g_sLogTableName);
1785
1786 #if defined CTBAN_DEBUG
1787 LogMessage("alter primary key query: %s", sQuery);
1788 #endif
1789
1790 SQL_TQuery(gH_BanDatabase, DB_Callback_UpgradeToLogTableTwo, sQuery);
1791 }
1792 }
1793}
1794
1795public void DB_Callback_UpgradeToLogTableTwo(Handle hOwner, Handle hCallback, const char[] sError, any data)
1796{
1797 if (hCallback == INVALID_HANDLE)
1798 {
1799 LogError("Error upgrading log table: %s", sError);
1800 SetFailState("Error while upgrading to Log Table Version Two. Exiting.");
1801 }
1802
1803 char sQuery[QUERY_MAXLENGTH];
1804 Format(sQuery, sizeof(sQuery), CTBAN_QUERY_LOG_TO_V2_ADD_BANID, g_sLogTableName);
1805
1806 #if defined CTBAN_DEBUG
1807 LogMessage("add ban_id query: %s", sQuery);
1808 #endif
1809
1810 SQL_TQuery(gH_BanDatabase, DB_Callback_LogError, sQuery, e_QueryLogTableTwo);
1811}
1812
1813public void DB_Callback_LogError(Handle hOwner, Handle hCallback, const char[] sError, any eCallback)
1814{
1815 if (hCallback == INVALID_HANDLE)
1816 {
1817 LogError("Error: %s", sError);
1818 }
1819 else
1820 {
1821 switch (eCallback)
1822 {
1823 case e_QueryLogTableTwo:
1824 {
1825 LogMessage("CTBan_Log Table Successfully Upgraded to Version Two");
1826 }
1827 }
1828 }
1829}
1830
1831public void DB_Callback_CreateTime(Handle hOwner, Handle hCallback, const char[] sError, any data)
1832{
1833 if (hCallback == INVALID_HANDLE)
1834 {
1835 LogError("Error establishing table creation: %s", sError);
1836 SetFailState("Unable to ascertain creation of table in default database. Exiting.");
1837 }
1838}
1839
1840public void DB_Callback_CreateLog(Handle hOwner, Handle hCallback, const char[] sError, any data)
1841{
1842 if (hCallback == INVALID_HANDLE)
1843 {
1844 LogError("Error establishing table creation: %s", sError);
1845 SetFailState("Unable to ascertain creation of table in default database. Exiting.");
1846 }
1847
1848 // Check the log table and upgrade to the new version if needed
1849 char sQuery[QUERY_MAXLENGTH];
1850
1851 Format(sQuery, sizeof(sQuery), CTBAN_QUERY_LOG_V1_CHECK, g_sLogTableName);
1852
1853 #if defined CTBAN_DEBUG
1854 LogMessage("check table version query %s", sQuery);
1855 #endif
1856
1857 SQL_TQuery(gH_BanDatabase, DB_Callback_CheckTableVersion, sQuery);
1858}
1859
1860public void CP_Callback_Connect(Handle hOwner, Handle hCallback, const char[] sError, any data)
1861{
1862 if (hCallback == INVALID_HANDLE)
1863 {
1864 LogError("Clientprefs database connection failure: %s", sError);
1865 SetFailState("Error while connecting to clientprefs database. Exiting.");
1866 }
1867 else
1868 {
1869 gH_CP_DataBase = hCallback;
1870
1871 // find the Banned_From_CT Cookie id #
1872 SQL_TQuery(gH_CP_DataBase, CP_Callback_FindCookie, CTBAN_QUERY_CP_FIND_COOKIE_ID);
1873 }
1874}
1875
1876public void CP_Callback_FindCookie(Handle hOwner, Handle hCallback, const char[] sError, any data)
1877{
1878 if (hCallback == INVALID_HANDLE)
1879 {
1880 LogError("Cookie query failure: %s", sError);
1881 }
1882 else
1883 {
1884 int iRowCount = SQL_GetRowCount(hCallback);
1885 if (iRowCount)
1886 {
1887 SQL_FetchRow(hCallback);
1888 int iCookieIDIndex = SQL_FetchInt(hCallback, FIND_COOKIE_CB_FIELD_COOKIE_ID);
1889 #if defined CTBAN_DEBUG
1890 LogMessage("found cookie index as %i", iCookieIDIndex);
1891 #endif
1892 g_iCookieIndex = iCookieIDIndex;
1893 }
1894 else
1895 {
1896 LogError("Could not find the cookie index. Rageban functionality disabled.");
1897 }
1898 }
1899}
1900
1901public void OnMapEnd()
1902{
1903 g_bIgnoreOverrideResets = true;
1904}
1905
1906public void OnMapStart()
1907{
1908 // pre-cache deny sound
1909 char sCommand[PLATFORM_MAX_PATH];
1910 GetConVarString(gH_Cvar_SoundName, gS_SoundPath, sizeof(gS_SoundPath));
1911 if(strcmp(gS_SoundPath, ""))
1912 {
1913 PrecacheSound(gS_SoundPath, true);
1914 Format(sCommand, sizeof(sCommand), "sound/%s", gS_SoundPath);
1915 AddFileToDownloadsTable(sCommand);
1916 }
1917
1918 g_bIgnoreOverrideResets = false;
1919}
1920
1921public void OnAdminMenuReady(Handle hTopMenu)
1922{
1923 // Block us from being called twice
1924 if (hTopMenu == gH_TopMenu)
1925 {
1926 return;
1927 }
1928
1929 // Save the Handle
1930 gH_TopMenu = hTopMenu;
1931
1932 // Build the "Player Commands" category
1933 TopMenuObject player_commands = FindTopMenuCategory(gH_TopMenu, ADMINMENU_PLAYERCOMMANDS);
1934
1935 if (player_commands != INVALID_TOPMENUOBJECT)
1936 {
1937 AddToTopMenu(gH_TopMenu,
1938 RAGEBAN_COMMAND,
1939 TopMenuObject_Item,
1940 AdminMenu_RageBan,
1941 player_commands,
1942 RAGEBAN_COMMAND,
1943 RAGEBAN_ADMIN_LEVEL);
1944
1945 AddToTopMenu(gH_TopMenu,
1946 CTBAN_COMMAND,
1947 TopMenuObject_Item,
1948 AdminMenu_CTBan,
1949 player_commands,
1950 CTBAN_COMMAND,
1951 CTBAN_ADMIN_LEVEL);
1952
1953 AddToTopMenu(gH_TopMenu,
1954 REMOVECTBAN_COMMAND,
1955 TopMenuObject_Item,
1956 AdminMenu_RemoveCTBan,
1957 player_commands,
1958 REMOVECTBAN_COMMAND,
1959 UNCTBAN_ADMIN_LEVEL);
1960
1961 AddToTopMenu(gH_TopMenu,
1962 FORCECT_COMMAND,
1963 TopMenuObject_Item,
1964 AdminMenu_ForceCT,
1965 player_commands,
1966 FORCECT_COMMAND,
1967 FORCECT_ADMIN_LEVEL);
1968
1969 AddToTopMenu(gH_TopMenu,
1970 UNFORCECT_COMMAND,
1971 TopMenuObject_Item,
1972 AdminMenu_UnForceCT,
1973 player_commands,
1974 UNFORCECT_COMMAND,
1975 UNFORCECT_ADMIN_LEVEL);
1976 }
1977}
1978
1979public void AdminMenu_ForceCT(Handle hTopMenu,
1980 TopMenuAction eAction,
1981 TopMenuObject eObjectID,
1982 int iClient,
1983 char[] sBuffer,
1984 int iMaxLength)
1985{
1986 if (eAction == TopMenuAction_DisplayOption)
1987 {
1988 Format(sBuffer, iMaxLength, "%T", "Force CT Admin Menu", iClient);
1989 }
1990 else if (eAction == TopMenuAction_SelectOption)
1991 {
1992 DisplayCTBannedPlayerMenu(iClient, e_ForceCT);
1993 }
1994}
1995
1996public void AdminMenu_UnForceCT(Handle hTopMenu,
1997 TopMenuAction eAction,
1998 TopMenuObject eObjectID,
1999 int iClient,
2000 char[] sBuffer,
2001 int iMaxLength)
2002{
2003 if (eAction == TopMenuAction_DisplayOption)
2004 {
2005 Format(sBuffer, iMaxLength, "%T", "UnForce CT Admin Menu", iClient);
2006 }
2007 else if (eAction == TopMenuAction_SelectOption)
2008 {
2009 DisplayUnForceCTPlayerMenu(iClient);
2010 }
2011}
2012
2013public void AdminMenu_RemoveCTBan(Handle hTopMenu,
2014 TopMenuAction eAction,
2015 TopMenuObject eObjectID,
2016 int iClient,
2017 char[] sBuffer,
2018 int iMaxLength)
2019{
2020 if (eAction == TopMenuAction_DisplayOption)
2021 {
2022 Format(sBuffer, iMaxLength, "%T", "Remove CT Ban Admin Menu", iClient);
2023 }
2024 else if (eAction == TopMenuAction_SelectOption)
2025 {
2026 DisplayCTBannedPlayerMenu(iClient, e_RemoveCTBan);
2027 }
2028}
2029
2030// displaying the list of CT Banned players is used by two commands
2031// default is for Remove CT Ban
2032// optional boolean is for CTBan List
2033void DisplayCTBannedPlayerMenu(int iClient, eCTBanMenuHandler eChoice)
2034{
2035 Handle hMenu = INVALID_HANDLE;
2036
2037 switch (eChoice)
2038 {
2039 case e_RemoveCTBan:
2040 {
2041 hMenu = CreateMenu(MenuHandler_RemoveCTBanPlayerList);
2042 SetMenuTitle(hMenu, "%T", "Remove CT Ban Menu Title", iClient);
2043 SetMenuExitBackButton(hMenu, true);
2044 }
2045 case e_CTBanList:
2046 {
2047 hMenu = CreateMenu(MenuHandler_CTBanList);
2048 SetMenuTitle(hMenu, "%T", "CTBanList Menu Title", iClient);
2049 SetMenuExitBackButton(hMenu, false);
2050 }
2051 case e_ForceCT:
2052 {
2053 hMenu = CreateMenu(MenuHandler_ForceCT);
2054 SetMenuTitle(hMenu, "%T", "Force CT Menu Title", iClient);
2055 SetMenuExitBackButton(hMenu, true);
2056 }
2057 }
2058
2059 int iCount = ZERO;
2060 char sUserId[MAX_USERID_LENGTH];
2061 char sName[MAX_NAME_LENGTH];
2062
2063 // display only people with existing CTBans
2064 for (int iIndex = ONE; iIndex <= MaxClients; iIndex++)
2065 {
2066 if (IsClientInGame(iIndex))
2067 {
2068 if (GetCTBanStatus(iIndex))
2069 {
2070 // Do no list people with overrides for Force CT Menu
2071 if (eChoice == e_ForceCT && g_bA_Temp_CTBan_Override[iIndex])
2072 {
2073 continue;
2074 }
2075
2076 IntToString(GetClientUserId(iIndex), sUserId, sizeof(sUserId));
2077 GetClientName(iIndex, sName, sizeof(sName));
2078
2079 AddMenuItem(hMenu, sUserId, sName);
2080
2081 iCount++;
2082 }
2083 }
2084 }
2085
2086 if (!iCount)
2087 {
2088 CPrintToChat(iClient, g_sChatBanner, "No matching clients");
2089 }
2090
2091 DisplayMenu(hMenu, iClient, MENU_TIME_FOREVER);
2092}
2093
2094public int MenuHandler_UnForceCT(Handle hMenu, MenuAction eAction, int iClient, int iMenuChoice)
2095{
2096 if (eAction == MenuAction_End)
2097 {
2098 CloseHandle(hMenu);
2099 }
2100 else if (eAction == MenuAction_Select)
2101 {
2102 char sTargetUserId[MAX_USERID_LENGTH];
2103 GetMenuItem(hMenu, iMenuChoice, sTargetUserId, sizeof(sTargetUserId));
2104 int iTargetUserId = StringToInt(sTargetUserId);
2105 int iTarget = GetClientOfUserId(iTargetUserId);
2106
2107 if (!iTarget || !IsClientInGame(iTarget))
2108 {
2109 CPrintToChat(iClient, g_sChatBanner, "Player no longer available");
2110 }
2111 else if (!g_bA_Temp_CTBan_Override[iTarget])
2112 {
2113 CPrintToChat(iClient, g_sChatBanner, "Player no longer available");
2114 }
2115 else
2116 {
2117 UnForceCTActions(iClient, iTarget);
2118 }
2119 }
2120}
2121
2122
2123public int MenuHandler_ForceCT(Handle hMenu, MenuAction eAction, int iClient, int iMenuChoice)
2124{
2125 if (eAction == MenuAction_End)
2126 {
2127 CloseHandle(hMenu);
2128 }
2129 else if (eAction == MenuAction_Select)
2130 {
2131 char sTargetUserId[MAX_USERID_LENGTH];
2132 GetMenuItem(hMenu, iMenuChoice, sTargetUserId, sizeof(sTargetUserId));
2133 int iTargetUserId = StringToInt(sTargetUserId);
2134 int iTarget = GetClientOfUserId(iTargetUserId);
2135
2136 if (!iTarget || !IsClientInGame(iTarget))
2137 {
2138 CPrintToChat(iClient, g_sChatBanner, "Player no longer available");
2139 }
2140 else if (GetClientTeam(iTarget) == CS_TEAM_CT)
2141 {
2142 CPrintToChat(iClient, g_sChatBanner, "Unable to target");
2143 }
2144 else
2145 {
2146 ForceCTActions(iClient, iTarget);
2147 }
2148 }
2149}
2150
2151public int MenuHandler_CTBanList(Handle hMenu, MenuAction eAction, int iClient, int iMenuChoice)
2152{
2153 if (eAction == MenuAction_End)
2154 {
2155 CloseHandle(hMenu);
2156 }
2157 else if (eAction == MenuAction_Select)
2158 {
2159 char sTargetUserId[MAX_USERID_LENGTH];
2160 GetMenuItem(hMenu, iMenuChoice, sTargetUserId, sizeof(sTargetUserId));
2161 int iTargetUserId = StringToInt(sTargetUserId);
2162 int iTarget = GetClientOfUserId(iTargetUserId);
2163
2164 if (!iTarget || !IsClientInGame(iTarget))
2165 {
2166 CPrintToChat(iClient, g_sChatBanner, "Player no longer available");
2167 }
2168 else if (!GetCTBanStatus(iTarget, iClient))
2169 {
2170 CPrintToChat(iClient, g_sChatBanner, "Not CT Banned", iTarget);
2171 }
2172 else
2173 {
2174 ProcessIsBannedTarget(iTarget, iClient);
2175 }
2176 }
2177}
2178
2179public int MenuHandler_RemoveCTBanPlayerList(Handle hMenu, MenuAction eAction, int iClient, int iMenuChoice)
2180{
2181 if (eAction == MenuAction_End)
2182 {
2183 CloseHandle(hMenu);
2184 }
2185 else if (eAction == MenuAction_Cancel)
2186 {
2187 if (iMenuChoice == MenuCancel_ExitBack && gH_TopMenu != INVALID_HANDLE)
2188 {
2189 DisplayTopMenu(gH_TopMenu, iClient, TopMenuPosition_LastCategory);
2190 }
2191 }
2192 else if (eAction == MenuAction_Select)
2193 {
2194 char sTargetUserId[MAX_USERID_LENGTH];
2195 GetMenuItem(hMenu, iMenuChoice, sTargetUserId, sizeof(sTargetUserId));
2196 int iTargetUserId = StringToInt(sTargetUserId);
2197 int iTarget = GetClientOfUserId(iTargetUserId);
2198
2199 if (!iTarget || !IsClientInGame(iTarget))
2200 {
2201 CPrintToChat(iClient, g_sChatBanner, "Player no longer available");
2202 }
2203 else if (!CanUserTarget(iClient, iTarget))
2204 {
2205 CPrintToChat(iClient, g_sChatBanner, "Unable to target");
2206 }
2207 else if (!GetCTBanStatus(iTarget, iClient))
2208 {
2209 CPrintToChat(iClient, g_sChatBanner, "Not CT Banned", iTarget);
2210 }
2211 else
2212 {
2213 if (AreClientCookiesCached(iTarget))
2214 {
2215 Remove_CTBan(iClient, iTarget);
2216 }
2217 else
2218 {
2219 ReplyToCommand(iClient, g_sChatBanner, "Cookie Status Unavailable");
2220 }
2221 }
2222 }
2223}
2224
2225public void AdminMenu_CTBan(Handle hTopMenu,
2226 TopMenuAction eAction,
2227 TopMenuObject eObjectID,
2228 int iClient,
2229 char[] sBuffer,
2230 int iMaxLength)
2231{
2232 if (eAction == TopMenuAction_DisplayOption)
2233 {
2234 Format(sBuffer, iMaxLength, "%T", "CT Ban Admin Menu", iClient);
2235 }
2236 else if (eAction == TopMenuAction_SelectOption)
2237 {
2238 DisplayCTBanPlayerMenu(iClient);
2239 }
2240}
2241
2242void DisplayCTBanPlayerMenu(int iClient)
2243{
2244 Handle hMenu = CreateMenu(MenuHandler_CTBanPlayerList);
2245
2246 SetMenuTitle(hMenu, "%T", "CT Ban Menu Title", iClient);
2247 SetMenuExitBackButton(hMenu, true);
2248
2249 int iCount = ZERO;
2250 char sUserId[MAX_USERID_LENGTH];
2251 char sName[MAX_NAME_LENGTH];
2252
2253 // filter away those with current CTBans
2254 for (int iIndex = ONE; iIndex <= MaxClients; iIndex++)
2255 {
2256 if (IsClientInGame(iIndex))
2257 {
2258 if (!GetCTBanStatus(iIndex))
2259 {
2260 IntToString(GetClientUserId(iIndex), sUserId, sizeof(sUserId));
2261 GetClientName(iIndex, sName, sizeof(sName));
2262
2263 AddMenuItem(hMenu, sUserId, sName);
2264
2265 iCount++;
2266 }
2267 }
2268 }
2269
2270 if (!iCount)
2271 {
2272 CPrintToChat(iClient, g_sChatBanner, "No Targets");
2273 }
2274
2275 DisplayMenu(hMenu, iClient, MENU_TIME_FOREVER);
2276}
2277
2278void DisplayCTBanTimeMenu(int iClient, int iTargetUserId)
2279{
2280 Handle hMenu = CreateMenu(MenuHandler_CTBanTimeList);
2281
2282 SetMenuTitle(hMenu, "%T", "CT Ban Length Menu", iClient, GetClientOfUserId(iTargetUserId));
2283 SetMenuExitBackButton(hMenu, true);
2284
2285 char sUserId[MAX_USERID_LENGTH];
2286 IntToString(iTargetUserId, sUserId, sizeof(sUserId));
2287 AddMenuItem(hMenu, sUserId, "", ITEMDRAW_IGNORE);
2288
2289 if (gH_KV_BanLengths != INVALID_HANDLE)
2290 {
2291 char sBanDuration[MAX_TIME_ARG_LENGTH];
2292 char sDurationDescription[MAX_TIME_INFO_STR_LENGTH];
2293
2294 KvGotoFirstSubKey(gH_KV_BanLengths, false);
2295 do
2296 {
2297 KvGetSectionName(gH_KV_BanLengths, sBanDuration, sizeof(sBanDuration));
2298 KvGetString(gH_KV_BanLengths, NULL_STRING, sDurationDescription, sizeof(sDurationDescription));
2299
2300 AddMenuItem(hMenu, sBanDuration, sDurationDescription);
2301 }
2302 while (KvGotoNextKey(gH_KV_BanLengths, false));
2303
2304 KvRewind(gH_KV_BanLengths);
2305 }
2306 else
2307 {
2308 AddMenuItem(hMenu, "0", "Permanent");
2309 AddMenuItem(hMenu, "5", "5 Minutes");
2310 // Only add 6 items in CS:GO menus so we don't paginate
2311 if (g_EngineVersion != Engine_CSGO)
2312 {
2313 AddMenuItem(hMenu, "10", "10 Minutes");
2314 }
2315 AddMenuItem(hMenu, "30", "30 Minutes");
2316 AddMenuItem(hMenu, "60", "1 Hour");
2317 AddMenuItem(hMenu, "120", "2 Hours");
2318 AddMenuItem(hMenu, "240", "4 Hours");
2319 }
2320
2321 DisplayMenu(hMenu, iClient, MENU_TIME_FOREVER);
2322}
2323
2324void DisplayCTBanReasonMenu(int iClient, int iTargetUserId, int iMinutesToBan)
2325{
2326 Handle hMenu = CreateMenu(MenuHandler_CTBanReasonList);
2327
2328 SetMenuTitle(hMenu, "%T", "CT Ban Reason Menu", iClient, GetClientOfUserId(iTargetUserId));
2329 SetMenuExitBackButton(hMenu, true);
2330
2331 char sTargetUserId[MAX_USERID_LENGTH];
2332 IntToString(iTargetUserId, sTargetUserId, sizeof(sTargetUserId));
2333 AddMenuItem(hMenu, sTargetUserId, "", ITEMDRAW_IGNORE);
2334
2335 char sTimeInMinutes[MAX_TIME_ARG_LENGTH];
2336 IntToString(iMinutesToBan, sTimeInMinutes, sizeof(sTimeInMinutes));
2337 AddMenuItem(hMenu, sTimeInMinutes, "", ITEMDRAW_IGNORE);
2338
2339 int iNumManualReasons = GetArraySize(gH_DArray_Reasons);
2340
2341 char sMenuReason[FIELD_REASON_MAXLENGTH];
2342 char sMenuInt[MAX_MENU_INT_CHOICE_LENGTH];
2343
2344 if (iNumManualReasons > ZERO)
2345 {
2346 for (int iLineNumber = ZERO; iLineNumber < iNumManualReasons; iLineNumber++)
2347 {
2348 GetArrayString(gH_DArray_Reasons, iLineNumber, sMenuReason, sizeof(sMenuReason));
2349 IntToString(iLineNumber, sMenuInt, sizeof(sMenuInt));
2350 AddMenuItem(hMenu, sMenuInt, sMenuReason);
2351 }
2352 }
2353 else
2354 {
2355 // Only display 6 reasons in CS:GO by default to avoid pagination
2356 // Freekill Massacre is a redundant reason with Freekilling "CT Ban Reason 5"
2357 if (g_EngineVersion != Engine_CSGO)
2358 {
2359 Format(sMenuReason, sizeof(sMenuReason), "%T", "CT Ban Reason 1", iClient);
2360 AddMenuItem(hMenu, "1", sMenuReason);
2361 }
2362 Format(sMenuReason, sizeof(sMenuReason), "%T", "CT Ban Reason 2", iClient);
2363 AddMenuItem(hMenu, "2", sMenuReason);
2364 Format(sMenuReason, sizeof(sMenuReason), "%T", "CT Ban Reason 3", iClient);
2365 AddMenuItem(hMenu, "3", sMenuReason);
2366 Format(sMenuReason, sizeof(sMenuReason), "%T", "CT Ban Reason 4", iClient);
2367 AddMenuItem(hMenu, "4", sMenuReason);
2368 Format(sMenuReason, sizeof(sMenuReason), "%T", "CT Ban Reason 5", iClient);
2369 AddMenuItem(hMenu, "5", sMenuReason);
2370 Format(sMenuReason, sizeof(sMenuReason), "%T", "CT Ban Reason 6", iClient);
2371 AddMenuItem(hMenu, "6", sMenuReason);
2372 Format(sMenuReason, sizeof(sMenuReason), "%T", "CT Ban Reason 7", iClient);
2373 AddMenuItem(hMenu, "7", sMenuReason);
2374 }
2375
2376 DisplayMenu(hMenu, iClient, MENU_TIME_FOREVER);
2377}
2378
2379public int MenuHandler_CTBanReasonList(Handle hMenu, MenuAction eAction, int iClient, int iMenuChoice)
2380{
2381 if (eAction == MenuAction_End)
2382 {
2383 CloseHandle(hMenu);
2384 }
2385 else if (eAction == MenuAction_Cancel)
2386 {
2387 if (iMenuChoice == MenuCancel_ExitBack && gH_TopMenu != INVALID_HANDLE)
2388 {
2389 DisplayTopMenu(gH_TopMenu, iClient, TopMenuPosition_LastCategory);
2390 }
2391 }
2392 else if (eAction == MenuAction_Select)
2393 {
2394 char sTargetUserId[MAX_USERID_LENGTH];
2395 GetMenuItem(hMenu, MENUCHOICE_USERID, sTargetUserId, sizeof(sTargetUserId));
2396 int iTargetUserId = StringToInt(sTargetUserId);
2397
2398 char sTimeInMinutes[MAX_TIME_ARG_LENGTH];
2399 GetMenuItem(hMenu, MENUCHOICE_TIME, sTimeInMinutes, sizeof(sTimeInMinutes));
2400 int iMinutesToBan = StringToInt(sTimeInMinutes);
2401
2402 char sBanChoice[MAX_REASON_MENU_CHOICE_LENGTH];
2403 GetMenuItem(hMenu, iMenuChoice, sBanChoice, sizeof(sBanChoice));
2404 int iBanReason = StringToInt(sBanChoice);
2405
2406 int iTarget = GetClientOfUserId(iTargetUserId);
2407
2408 if (!GetCTBanStatus(iTarget))
2409 {
2410 PerformCTBan(iTarget, iClient, iMinutesToBan, iBanReason);
2411 }
2412 else
2413 {
2414 CPrintToChat(iClient, g_sChatBanner, "Already CT Banned", iTarget);
2415 }
2416 }
2417}
2418
2419public int MenuHandler_CTBanPlayerList(Handle hMenu, MenuAction eAction, int iClient, int iMenuChoice)
2420{
2421 if (eAction == MenuAction_End)
2422 {
2423 CloseHandle(hMenu);
2424 }
2425 else if (eAction == MenuAction_Cancel)
2426 {
2427 if (iMenuChoice == MenuCancel_ExitBack && gH_TopMenu != INVALID_HANDLE)
2428 {
2429 DisplayTopMenu(gH_TopMenu, iClient, TopMenuPosition_LastCategory);
2430 }
2431 }
2432 else if (eAction == MenuAction_Select)
2433 {
2434 char sTargetUserId[MAX_USERID_LENGTH];
2435 GetMenuItem(hMenu, iMenuChoice, sTargetUserId, sizeof(sTargetUserId));
2436 int iTargetUserId = StringToInt(sTargetUserId);
2437 int iTarget = GetClientOfUserId(iTargetUserId);
2438
2439 if (!iTarget || !IsClientInGame(iTarget))
2440 {
2441 CPrintToChat(iClient, g_sChatBanner, "Player no longer available");
2442 }
2443 else if (!CanUserTarget(iClient, iTarget))
2444 {
2445 CPrintToChat(iClient, g_sChatBanner, "Unable to target");
2446 }
2447 else if (GetCTBanStatus(iTarget, iClient))
2448 {
2449 CPrintToChat(iClient, g_sChatBanner, "Already CT Banned", iTarget);
2450 }
2451 else
2452 {
2453 DisplayCTBanTimeMenu(iClient, iTargetUserId);
2454 }
2455 }
2456}
2457
2458public int MenuHandler_CTBanTimeList(Handle hMenu, MenuAction eAction, int iClient, int iMenuChoice)
2459{
2460 if (eAction == MenuAction_End)
2461 {
2462 CloseHandle(hMenu);
2463 }
2464 else if (eAction == MenuAction_Cancel)
2465 {
2466 if (iMenuChoice == MenuCancel_ExitBack && gH_TopMenu != INVALID_HANDLE)
2467 {
2468 DisplayTopMenu(gH_TopMenu, iClient, TopMenuPosition_LastCategory);
2469 }
2470 }
2471 else if (eAction == MenuAction_Select)
2472 {
2473 char sTargetUserId[MAX_USERID_LENGTH];
2474 GetMenuItem(hMenu, MENUCHOICE_USERID, sTargetUserId, sizeof(sTargetUserId));
2475 int iTargetUserId = StringToInt(sTargetUserId);
2476
2477 char sTimeInMinutes[MAX_TIME_ARG_LENGTH];
2478 GetMenuItem(hMenu, iMenuChoice, sTimeInMinutes, sizeof(sTimeInMinutes));
2479 int iMinutesToBan = StringToInt(sTimeInMinutes);
2480
2481 DisplayCTBanReasonMenu(iClient, iTargetUserId, iMinutesToBan);
2482 }
2483}
2484
2485public void OnClientConnected(int iClient)
2486{
2487 g_bA_Temp_CTBan_Override[iClient] = false;
2488}
2489
2490public void OnClientPostAdminCheck(int iClient)
2491{
2492 CreateTimer(COOKIE_INIT_CHECK_TIME, Timer_CheckBanCookies, iClient, TIMER_FLAG_NO_MAPCHANGE);
2493}
2494
2495public void OnClientDisconnect(int iClient)
2496{
2497 char sDisconnectSteamID[FIELD_AUTHID_MAXLENGTH];
2498 GetClientAuthId(iClient, AuthId_Steam2, sDisconnectSteamID, sizeof(sDisconnectSteamID));
2499
2500 // add information to rage ban list
2501 char sName[MAX_TARGET_LENGTH];
2502 GetClientName(iClient, sName, sizeof(sName));
2503
2504 // add information to array
2505 // if information isn't already in the arrays then add it
2506 if (FindStringInArray(gA_DSteamIDs, sDisconnectSteamID) == VALUE_NOT_FOUND_IN_ARRAY)
2507 {
2508 g_bRageBanArrayChanged = true;
2509
2510 PushArrayString(gA_DNames, sName);
2511 PushArrayString(gA_DSteamIDs, sDisconnectSteamID);
2512
2513 if (GetArraySize(gA_DNames) >= (g_EngineVersion == Engine_CSGO ? CSGO_MAX_PAGE_MENU_ITEMS : CSS_MAX_PAGE_MENU_ITEMS))
2514 {
2515 // Remove the oldest entry
2516 RemoveFromArray(gA_DNames, ZERO);
2517 RemoveFromArray(gA_DSteamIDs, ZERO);
2518 }
2519 }
2520
2521 // check if they were in the timed array
2522 int iBannedArrayIndex = FindValueInArray(gA_TimedBanLocalList, iClient);
2523 if (iBannedArrayIndex != VALUE_NOT_FOUND_IN_ARRAY)
2524 {
2525 // remove them from the local array
2526 RemoveFromArray(gA_TimedBanLocalList, iBannedArrayIndex);
2527
2528 // make a datapack for the next query
2529 Handle hDisconnectPack = CreateDataPack();
2530 WritePackCell(hDisconnectPack, iClient);
2531 WritePackString(hDisconnectPack, sDisconnectSteamID);
2532
2533 // update steam array
2534 char sQuery[QUERY_MAXLENGTH];
2535 Format(sQuery, sizeof(sQuery), CTBAN_QUERY_TIME_SELECT_BANTIME, g_sTimesTableName, sDisconnectSteamID);
2536 SQL_TQuery(gH_BanDatabase, DB_Callback_ClientDisconnect, sQuery, hDisconnectPack);
2537 }
2538
2539 // if there are no admins left then swap all the !forcect players back to T team!
2540 bool bAdminPresent = false;
2541 for (int iIndex = ONE; iIndex <= MaxClients; iIndex++)
2542 {
2543 if (IsClientInGame(iIndex))
2544 {
2545 if (CheckCommandAccess(iIndex, FORCECT_COMMAND, ADMFLAG_SLAY))
2546 {
2547 bAdminPresent = true;
2548 break;
2549 }
2550 }
2551 }
2552
2553 // if no admins are present then move *everyone* back to Terrorist team who has an override
2554 if (!bAdminPresent && !g_bIgnoreOverrideResets)
2555 {
2556 for (int iIndex = ONE; iIndex <= MaxClients; iIndex++)
2557 {
2558 UnForceCTActions(ZERO, iIndex, true);
2559 }
2560 }
2561}
2562
2563public void DB_Callback_ClientDisconnect(Handle hOwner, Handle hCallback, const char[] sError, any hDataPack)
2564{
2565 if (hCallback == INVALID_HANDLE)
2566 {
2567 LogError("Error with query on client disconnect: %s", sError);
2568 CloseHandle(hDataPack);
2569 }
2570 else
2571 {
2572 ResetPack(hDataPack);
2573 int iClient = ReadPackCell(hDataPack);
2574 char sAuthID[FIELD_AUTHID_MAXLENGTH];
2575 ReadPackString(hDataPack, sAuthID, sizeof(sAuthID));
2576
2577 int iRowCount = SQL_GetRowCount(hCallback);
2578 if (iRowCount)
2579 {
2580 #if defined CTBAN_DEBUG
2581 SQL_FetchRow(hCallback);
2582 int iBanTimeRemaining = SQL_FetchInt(hCallback, CLIENT_DISCONNECT_CB_FIELD_TIMELEFT);
2583
2584 if (IsClientInGame(iClient))
2585 {
2586 LogMessage("SQL: %N disconnected with %i time remaining on ban", iClient, iBanTimeRemaining);
2587 }
2588 else
2589 {
2590 LogMessage("SQL: %i client index disconnected with %i time remaining on ban", iClient, iBanTimeRemaining);
2591 }
2592 #endif
2593
2594 char sQuery[QUERY_MAXLENGTH];
2595 if (gA_LocalTimeRemaining[iClient] <= ZERO)
2596 {
2597 // remove steam array
2598 Format(sQuery, sizeof(sQuery), CTBAN_QUERY_TIME_DELETE, g_sTimesTableName, sAuthID);
2599 SQL_TQuery(gH_BanDatabase, DB_Callback_DisconnectAction, sQuery);
2600
2601 Format(sQuery, sizeof(sQuery), CTBAN_QUERY_LOG_EXPIRE, g_sLogTableName, sAuthID);
2602 SQL_TQuery(gH_BanDatabase, DB_Callback_DisconnectAction, sQuery);
2603 }
2604 else
2605 {
2606 // update the time
2607 Format(sQuery, sizeof(sQuery), CTBAN_QUERY_TIME_UPDATE, g_sTimesTableName, gA_LocalTimeRemaining[iClient], sAuthID);
2608 SQL_TQuery(gH_BanDatabase, DB_Callback_DisconnectAction, sQuery);
2609
2610 Format(sQuery, sizeof(sQuery), CTBAN_QUERY_LOG_UPDATE, g_sLogTableName, gA_LocalTimeRemaining[iClient], sAuthID);
2611 SQL_TQuery(gH_BanDatabase, DB_Callback_DisconnectAction, sQuery);
2612 }
2613 }
2614 }
2615}
2616
2617public void DB_Callback_DisconnectAction(Handle hOwner, Handle hCallback, const char[] sError, any data)
2618{
2619 if (hCallback == INVALID_HANDLE)
2620 {
2621 LogError("Error with updating/deleting record after client disconnect: %s", sError);
2622 }
2623}
2624
2625public Action Timer_CheckBanCookies(Handle hTimer, any iClient)
2626{
2627 if (AreClientCookiesCached(iClient))
2628 {
2629 ProcessBanCookies(iClient);
2630 }
2631 else if(IsClientInGame(iClient))
2632 {
2633 CreateTimer(COOKIE_RESCAN_TIME, Timer_CheckBanCookies, iClient, TIMER_FLAG_NO_MAPCHANGE);
2634 }
2635}
2636
2637void ProcessBanCookies(int iClient)
2638{
2639 if(iClient && IsClientInGame(iClient))
2640 {
2641 if (GetCTBanStatus(iClient))
2642 {
2643 // check to see if they joined CT
2644 if (GetClientTeam(iClient) == CS_TEAM_CT)
2645 {
2646 EnforceCTBan(iClient);
2647 }
2648 }
2649 }
2650}
2651
2652public Action Command_UnCTBan(int iClient, int iArgs)
2653{
2654 if (!iClient && !iArgs)
2655 {
2656 char sCommandName[MAX_UNBAN_CMD_LENGTH];
2657 // position 0 retrieves the command name. Could be unctban or removectban.
2658 GetCmdArg(ARG_ZERO_GET_COMMAND_NAME, sCommandName, sizeof(sCommandName));
2659 StrCat(sCommandName, sizeof(sCommandName), " <player>");
2660
2661 ReplyToCommand(iClient, g_sChatBanner, "Command Usage", sCommandName);
2662 return Plugin_Handled;
2663 }
2664
2665 if (!iArgs)
2666 {
2667 DisplayCTBannedPlayerMenu(iClient, e_RemoveCTBan);
2668 }
2669 else
2670 {
2671 char sTarget[MAX_NAME_LENGTH];
2672 GetCmdArg(UNCTBAN_ARG_TARGET, sTarget, sizeof(sTarget));
2673
2674 char sClientName[MAX_TARGET_LENGTH];
2675 int aiTargetList[MAXPLAYERS];
2676 int iTargetCount;
2677 bool b_tn_is_ml;
2678 iTargetCount = ProcessTargetString(sTarget, iClient, aiTargetList, MAXPLAYERS, COMMAND_FILTER_NO_MULTI, sClientName, sizeof(sClientName), b_tn_is_ml);
2679
2680 if (iTargetCount < ONE)
2681 {
2682 ReplyToTargetError(iClient, iTargetCount);
2683 }
2684 else
2685 {
2686 int iTarget = aiTargetList[ZERO];
2687 // check if the cookies are ready
2688 if (AreClientCookiesCached(iTarget))
2689 {
2690 Remove_CTBan(iClient, iTarget);
2691 }
2692 else
2693 {
2694 ReplyToCommand(iClient, g_sChatBanner, "Cookie Status Unavailable");
2695 }
2696 }
2697 }
2698
2699 return Plugin_Handled;
2700}
2701
2702void Remove_CTBan(int iAdmin, int iTarget, bool bExpired=false)
2703{
2704 if (GetCTBanStatus(iTarget))
2705 {
2706 char sTargetSteam[FIELD_AUTHID_MAXLENGTH];
2707 GetClientAuthId(iTarget, AuthId_Steam2, sTargetSteam, sizeof(sTargetSteam));
2708
2709 char sQuery[QUERY_MAXLENGTH];
2710 Format(sQuery, sizeof(sQuery), CTBAN_QUERY_LOG_EXPIRE, g_sLogTableName, sTargetSteam);
2711
2712 #if defined CTBAN_DEBUG
2713 LogMessage("log query: %s", sQuery);
2714 #endif
2715
2716 SQL_TQuery(gH_BanDatabase, DB_Callback_RemoveCTBan, sQuery, iTarget);
2717
2718 LogMessage("%N has removed the CT ban on %N (%s).", iAdmin, iTarget, sTargetSteam);
2719
2720 if (!bExpired)
2721 {
2722 ShowActivity2(iAdmin, "", g_sChatBanner, "CT Ban Removed", iTarget);
2723 }
2724 else
2725 {
2726 ShowActivity2(iAdmin, "", g_sChatBanner, "CT Ban Auto Removed", iTarget);
2727 }
2728
2729 // delete from the timedban database if there was one
2730 Format(sQuery, sizeof(sQuery), CTBAN_QUERY_TIME_DELETE, g_sTimesTableName, sTargetSteam);
2731
2732 SQL_TQuery(gH_BanDatabase, DB_Callback_RemoveCTBan, sQuery, iTarget);
2733 }
2734 else
2735 {
2736 ReplyToCommand(iAdmin, g_sChatBanner, "Not CT Banned", iTarget);
2737 }
2738
2739 // error on side of caution and just set cookie to 0 regardless of what it was
2740 SetClientCookie(iTarget, g_CT_Cookie, COOKIE_UNBANNED_STRING);
2741
2742 g_bA_Temp_CTBan_Override[iTarget] = false;
2743
2744 Call_StartForward(g_hFrwd_OnUnCTBan);
2745 Call_PushCell(iTarget);
2746 Call_PushCell(iAdmin);
2747 Call_Finish();
2748}
2749
2750public void DB_Callback_RemoveCTBan(Handle hOwner, Handle hCallback, const char[] sError, any iClient)
2751{
2752 if (hCallback == INVALID_HANDLE)
2753 {
2754 LogError("Error handling steamID after CT ban removal: %s", sError);
2755 }
2756 else
2757 {
2758 #if defined CTBAN_DEBUG
2759 if (iClient > ZERO && IsClientInGame(iClient))
2760 {
2761 LogMessage("CTBan on %N was removed in SQL", iClient);
2762 }
2763 else
2764 {
2765 LogMessage("CTBan on --- was removed in SQL");
2766 }
2767 #endif
2768 }
2769}
2770
2771public Action Command_CTBan(int iClient, int iArgs)
2772{
2773 if (!iClient && (iArgs < (GetConVarBool(gH_Cvar_Force_Reason) ? CTBAN_ARG_REASON : CTBAN_ARG_TIME)))
2774 {
2775 if (GetConVarBool(gH_Cvar_Force_Reason))
2776 {
2777 ReplyToCommand(iClient, g_sChatBanner, "Command Usage", "sm_ctban <player> <time> <reason>");
2778 }
2779 else
2780 {
2781 ReplyToCommand(iClient, g_sChatBanner, "Command Usage", "sm_ctban <player> <time> <optional:reason>");
2782 }
2783
2784 return Plugin_Handled;
2785 }
2786
2787 if (!iArgs)
2788 {
2789 DisplayCTBanPlayerMenu(iClient);
2790 return Plugin_Handled;
2791 }
2792
2793 char sTarget[MAX_NAME_LENGTH];
2794 GetCmdArg(CTBAN_ARG_PLAYER, sTarget, sizeof(sTarget));
2795
2796 char sClientName[MAX_TARGET_LENGTH];
2797 int aiTargetList[MAXPLAYERS];
2798 int iTargetCount;
2799 bool b_tn_is_ml;
2800 iTargetCount = ProcessTargetString(sTarget, iClient, aiTargetList, MAXPLAYERS, COMMAND_FILTER_NO_MULTI, sClientName, sizeof(sClientName), b_tn_is_ml);
2801
2802 // target count 0 or less is an error condition
2803 if (iTargetCount < ONE)
2804 {
2805 ReplyToTargetError(iClient, iTargetCount);
2806 }
2807 else
2808 {
2809 int iTarget = aiTargetList[ZERO];
2810
2811 if(iTarget && IsClientInGame(iTarget))
2812 {
2813 if (GetCTBanStatus(iTarget, iClient))
2814 {
2815 ReplyToCommand(iClient, g_sChatBanner, "Already CT Banned", iTarget);
2816 }
2817 else
2818 {
2819 if (iArgs == CTBAN_ARG_PLAYER)
2820 {
2821 int iTargetUserId = GetClientUserId(iTarget);
2822 DisplayCTBanTimeMenu(iClient, iTargetUserId);
2823 return Plugin_Handled;
2824 }
2825
2826 char sBanTime[MAX_TIME_ARG_LENGTH];
2827 GetCmdArg(CTBAN_ARG_TIME, sBanTime, sizeof(sBanTime));
2828 int iBanTime = StringToInt(sBanTime);
2829
2830 if (GetConVarBool(gH_Cvar_Force_Reason) && iArgs == CTBAN_ARG_TIME)
2831 {
2832 int iTargetUserId = GetClientUserId(iTarget);
2833 DisplayCTBanReasonMenu(iClient, iTargetUserId, iBanTime);
2834 return Plugin_Handled;
2835 }
2836
2837 char sReasonStr[FIELD_REASON_MAXLENGTH];
2838 char sArgPart[FIELD_REASON_MAXLENGTH];
2839 for (int iArg = CTBAN_ARG_REASON; iArg <= iArgs; iArg++)
2840 {
2841 GetCmdArg(iArg, sArgPart, sizeof(sArgPart));
2842 Format(sReasonStr, sizeof(sReasonStr), "%s %s", sReasonStr, sArgPart);
2843 }
2844 // Remove the space at the beginning
2845 TrimString(sReasonStr);
2846
2847 if (GetConVarBool(gH_Cvar_Force_Reason) && !strlen(sReasonStr))
2848 {
2849 ReplyToCommand(iClient, g_sChatBanner, "Reason Required");
2850 }
2851 else
2852 {
2853 PerformCTBan(iTarget, iClient, iBanTime, _, sReasonStr);
2854 }
2855 }
2856 }
2857 }
2858 return Plugin_Handled;
2859}
2860
2861void PerformCTBan(int iClient, int iAdmin, int iBanTime = CTBAN_PERM_BAN_LENGTH, int iReason = CTBAN_NO_REASON_GIVEN, char[] sManualReason="")
2862{
2863 // set cookie to ban
2864 SetClientCookie(iClient, g_CT_Cookie, COOKIE_BANNED_STRING);
2865
2866 char sTargetAuthID[FIELD_AUTHID_MAXLENGTH];
2867 GetClientAuthId(iClient, AuthId_Steam2, sTargetAuthID, sizeof(sTargetAuthID));
2868
2869 // check if they're on CT team
2870 if (GetClientTeam(iClient) == CS_TEAM_CT)
2871 {
2872 EnforceCTBan(iClient);
2873 }
2874
2875 char sReason[FIELD_REASON_MAXLENGTH];
2876 if (strlen(sManualReason) > ZERO)
2877 {
2878 Format(sReason, sizeof(sReason), "%s", sManualReason);
2879 }
2880 // or else they picked a reason # from the admin menu
2881 else
2882 {
2883 // Check if we are using the translated phrase reasons or the manual file reasons
2884 int iNumManualReasons = GetArraySize(gH_DArray_Reasons);
2885
2886 // manual file reasons
2887 if (iNumManualReasons > ZERO)
2888 {
2889 if (iReason == CTBAN_NO_REASON_GIVEN)
2890 {
2891 Format(sReason, sizeof(sReason), "No reason given.");
2892 }
2893 else
2894 {
2895 GetArrayString(gH_DArray_Reasons, iReason, sReason, sizeof(sReason));
2896 }
2897 }
2898 // translated phrases reasons
2899 else
2900 {
2901 switch (iReason)
2902 {
2903 case ONE:
2904 {
2905 Format(sReason, sizeof(sReason), "%T", "CT Ban Reason 1", iAdmin);
2906 }
2907 case TWO:
2908 {
2909 Format(sReason, sizeof(sReason), "%T", "CT Ban Reason 2", iAdmin);
2910 }
2911 case THREE:
2912 {
2913 Format(sReason, sizeof(sReason), "%T", "CT Ban Reason 3", iAdmin);
2914 }
2915 case FOUR:
2916 {
2917 Format(sReason, sizeof(sReason), "%T", "CT Ban Reason 4", iAdmin);
2918 }
2919 case FIVE:
2920 {
2921 Format(sReason, sizeof(sReason), "%T", "CT Ban Reason 5", iAdmin);
2922 }
2923 case SIX:
2924 {
2925 Format(sReason, sizeof(sReason), "%T", "CT Ban Reason 6", iAdmin);
2926 }
2927 case SEVEN:
2928 {
2929 Format(sReason, sizeof(sReason), "%T", "CT Ban Reason 7", iAdmin);
2930 }
2931 default:
2932 {
2933 Format(sReason, sizeof(sReason), "No reason given.");
2934 }
2935 }
2936 }
2937 }
2938
2939 int iTimeStamp = GetTime();
2940
2941 char sTempName[FIELD_NAME_MAXLENGTH];
2942 char sQuery[QUERY_MAXLENGTH];
2943
2944 char sEscapedPerpName[MAX_SAFE_ESCAPE_QUERY(FIELD_NAME_MAXLENGTH)];
2945 Format(sTempName, sizeof(sTempName), "%N", iClient);
2946 SQL_EscapeString(gH_BanDatabase, sTempName, sEscapedPerpName, sizeof(sEscapedPerpName));
2947
2948 char sEscapedReason[MAX_SAFE_ESCAPE_QUERY(FIELD_REASON_MAXLENGTH)];
2949 SQL_EscapeString(gH_BanDatabase, sReason, sEscapedReason, sizeof(sEscapedReason));
2950
2951 if(iAdmin && IsClientInGame(iAdmin))
2952 {
2953 char sAdminAuthID[FIELD_AUTHID_MAXLENGTH];
2954 GetClientAuthId(iAdmin, AuthId_Steam2, sAdminAuthID, sizeof(sAdminAuthID));
2955
2956 char sEscapedAdminName[MAX_SAFE_ESCAPE_QUERY(FIELD_NAME_MAXLENGTH)];
2957 Format(sTempName, sizeof(sTempName), "%N", iAdmin);
2958 SQL_EscapeString(gH_BanDatabase, sTempName, sEscapedAdminName, sizeof(sEscapedAdminName));
2959
2960 Format(sQuery, sizeof(sQuery), CTBAN_QUERY_LOG_INSERT, g_sLogTableName, iTimeStamp, sTargetAuthID, sEscapedPerpName, sAdminAuthID, sEscapedAdminName, iBanTime, iBanTime, sEscapedReason);
2961
2962 #if defined CTBAN_DEBUG
2963 LogMessage("log query: %s", sQuery);
2964 #endif
2965
2966 SQL_TQuery(gH_BanDatabase, DB_Callback_CTBan, sQuery, iClient);
2967
2968 LogMessage("%N (%s) has issued a CT ban on %N (%s) for %d minutes for %s.", iAdmin, sAdminAuthID, iClient, sTargetAuthID, iBanTime, sReason);
2969 }
2970 else
2971 {
2972 Format(sQuery, sizeof(sQuery), CTBAN_QUERY_LOG_INSERT, g_sLogTableName, iTimeStamp, sTargetAuthID, sEscapedPerpName, CONSOLE_AUTHID, CONSOLE_USER_NAME, iBanTime, iBanTime, sEscapedReason);
2973
2974 #if defined CTBAN_DEBUG
2975 LogMessage("log query: %s", sQuery);
2976 #endif
2977
2978 SQL_TQuery(gH_BanDatabase, DB_Callback_CTBan, sQuery, iClient);
2979
2980 LogMessage("Console has issued a CT ban on %N (%s) for %d.", iClient, sTargetAuthID, iBanTime);
2981 }
2982
2983 // check if there is a time
2984 if (iBanTime > CTBAN_PERM_BAN_LENGTH)
2985 {
2986 ShowActivity2(iAdmin, "", g_sChatBanner, "Temporary CT Ban and Reason", iClient, iBanTime, sReason);
2987 // save in local quick-access array
2988 PushArrayCell(gA_TimedBanLocalList, iClient);
2989 gA_LocalTimeRemaining[iClient] = iBanTime;
2990
2991 // save in long-term database (already guaranteed to run only once per steam ID)
2992 switch (g_eDatabaseType)
2993 {
2994 case e_SQLite:
2995 {
2996 Format(sQuery, sizeof(sQuery), CTBAN_QUERY_TIME_INSERT_SQLITE, g_sTimesTableName, sTargetAuthID, iBanTime);
2997 }
2998 default:
2999 {
3000 Format(sQuery, sizeof(sQuery), CTBAN_QUERY_TIME_INSERT_MYSQL, g_sTimesTableName, sTargetAuthID, iBanTime, iBanTime);
3001 }
3002 }
3003
3004 #if defined CTBAN_DEBUG
3005 LogMessage("ctban query: %s", sQuery);
3006 #endif
3007
3008 SQL_TQuery(gH_BanDatabase, DB_Callback_CTBan, sQuery, iClient);
3009 }
3010 else
3011 {
3012 ShowActivity2(iAdmin, "", g_sChatBanner, "Permanent CT Ban and Reason", iClient, sReason);
3013 }
3014
3015 Call_StartForward(g_hFrwd_OnCTBan);
3016 Call_PushCell(iClient);
3017 Call_PushCell(iAdmin);
3018 Call_PushCell(iBanTime);
3019 Call_PushString(sReason);
3020 Call_Finish();
3021}
3022
3023public void DB_Callback_CTBan(Handle hOwner, Handle hCallback, const char[] sError, any iClient)
3024{
3025 if (hCallback == INVALID_HANDLE)
3026 {
3027 LogError("Error writing CTBan to Timed Ban database: %s", sError);
3028 }
3029 else
3030 {
3031 #if defined CTBAN_DEBUG
3032 if (iClient > ZERO && IsClientInGame(iClient))
3033 {
3034 LogMessage("SQL CTBan: Updated database with CT Ban for %N", iClient);
3035 }
3036 #endif
3037 }
3038}
3039
3040public Action Command_Change_CTBan_Time(int iClient, int iArgs)
3041{
3042 if (iArgs != CHANGE_TIME_ARG_TIME)
3043 {
3044 ReplyToCommand(iClient, g_sChatBanner, "Command Usage", "sm_change_ctban_time <player> <time>");
3045 return Plugin_Handled;
3046 }
3047
3048 char sTarget[MAX_TARGET_LENGTH];
3049 GetCmdArg(CHANGE_TIME_ARG_TARGET, sTarget, sizeof(sTarget));
3050
3051 char sClientName[MAX_TARGET_LENGTH];
3052 int aiTargetList[MAXPLAYERS];
3053 int iTargetCount;
3054 bool b_tn_is_ml;
3055 iTargetCount = ProcessTargetString(sTarget, iClient, aiTargetList, MAXPLAYERS, COMMAND_FILTER_NO_MULTI, sClientName, sizeof(sClientName), b_tn_is_ml);
3056 if (iTargetCount < ONE)
3057 {
3058 ReplyToTargetError(iClient, iTargetCount);
3059 }
3060 else
3061 {
3062 int iTarget = aiTargetList[ZERO];
3063 if (GetCTBanStatus(iTarget))
3064 {
3065 char sTime[MAX_TIME_ARG_LENGTH];
3066 GetCmdArg(CHANGE_TIME_ARG_TIME, sTime, sizeof(sTime));
3067
3068 int iTime = StringToInt(sTime);
3069
3070 if (iTime < ZERO)
3071 {
3072 ReplyToCommand(iClient, g_sChatBanner, "Invalid Amount");
3073 }
3074 // check if time is not changing
3075 else if (gA_LocalTimeRemaining[iTarget] == iTime || (gA_LocalTimeRemaining[iTarget] <= ZERO && iTime == ZERO))
3076 {
3077 ReplyToCommand(iClient, g_sChatBanner, "Invalid Amount");
3078 }
3079 else
3080 {
3081 PerformChangeCTBanTime(iTarget, iClient, iTime);
3082 }
3083 }
3084 else
3085 {
3086 ReplyToCommand(iClient, g_sChatBanner, "Not CT Banned", iTarget);
3087 }
3088 }
3089
3090 return Plugin_Handled;
3091}
3092
3093void PerformChangeCTBanTime(int iTarget, int iClient, int iTime)
3094{
3095 // 3 types of possible actions depending on the existing and new ban type
3096 // timed to timed
3097 if (iTime > ZERO && gA_LocalTimeRemaining[iTarget] > ZERO)
3098 {
3099 gA_LocalTimeRemaining[iTarget] = iTime;
3100
3101 ShowActivity2(iClient, "", g_sChatBanner, "Temporary CT Ban", iTarget, iTime);
3102
3103 // if it is a timed to timed change then the values will be cached on client disconnect like normal
3104 }
3105 // timed to perm
3106 else if (iTime == ZERO && gA_LocalTimeRemaining[iTarget] > ZERO)
3107 {
3108 gA_LocalTimeRemaining[iTarget] = iTime;
3109
3110 // check if they were in the timed array
3111 int iBannedArrayIndex = FindValueInArray(gA_TimedBanLocalList, iTarget);
3112 if (iBannedArrayIndex != VALUE_NOT_FOUND_IN_ARRAY)
3113 {
3114 // remove them from the local array
3115 RemoveFromArray(gA_TimedBanLocalList, iBannedArrayIndex);
3116
3117 char sAuthId[FIELD_AUTHID_MAXLENGTH];
3118 GetClientAuthId(iTarget, AuthId_Steam2, sAuthId, sizeof(sAuthId));
3119
3120 // fix these tables so it will not reset on the next server join
3121 char sQuery[QUERY_MAXLENGTH];
3122 Format(sQuery, sizeof(sQuery), CTBAN_QUERY_TIME_DELETE, g_sTimesTableName, sAuthId);
3123 SQL_TQuery(gH_BanDatabase, DB_Callback_DisconnectAction, sQuery);
3124
3125 switch (g_eDatabaseType)
3126 {
3127 case e_SQLite:
3128 {
3129 Format(sQuery, sizeof(sQuery), CTBAN_QUERY_LOG_TIME_TO_PERM_SQLITE, g_sLogTableName, sAuthId);
3130 }
3131 default:
3132 {
3133 Format(sQuery, sizeof(sQuery), CTBAN_QUERY_LOG_TIME_TO_PERM_MYSQL, g_sLogTableName, sAuthId);
3134 }
3135 }
3136 SQL_TQuery(gH_BanDatabase, DB_Callback_DisconnectAction, sQuery);
3137 }
3138
3139 ShowActivity2(iClient, "", g_sChatBanner, "Permanent CT Ban", iTarget);
3140 }
3141 // perm to timed
3142 else if (iTime > ZERO && gA_LocalTimeRemaining[iTarget] <= ZERO)
3143 {
3144 // save in local quick-access array
3145 PushArrayCell(gA_TimedBanLocalList, iTarget);
3146 gA_LocalTimeRemaining[iTarget] = iTime;
3147
3148 char sAuthId[FIELD_AUTHID_MAXLENGTH];
3149 GetClientAuthId(iTarget, AuthId_Steam2, sAuthId, sizeof(sAuthId));
3150
3151 // save in long-term database (already guaranteed to run only once per steam ID)
3152 char sQuery[QUERY_MAXLENGTH];
3153 switch (g_eDatabaseType)
3154 {
3155 case e_SQLite:
3156 {
3157 Format(sQuery, sizeof(sQuery), CTBAN_QUERY_TIME_INSERT_SQLITE, g_sTimesTableName, sAuthId, iTime);
3158 }
3159 default:
3160 {
3161 Format(sQuery, sizeof(sQuery), CTBAN_QUERY_TIME_INSERT_MYSQL, g_sTimesTableName, sAuthId, iTime, iTime);
3162 }
3163 }
3164 #if defined CTBAN_DEBUG
3165 LogMessage("ctban query: %s", sQuery);
3166 #endif
3167 SQL_TQuery(gH_BanDatabase, DB_Callback_DisconnectAction, sQuery);
3168
3169 switch (g_eDatabaseType)
3170 {
3171 case e_SQLite:
3172 {
3173 Format(sQuery, sizeof(sQuery), CTBAN_QUERY_LOG_PERM_TO_TIME_SQLITE, g_sLogTableName, iTime, iTime, sAuthId);
3174 }
3175 default:
3176 {
3177 Format(sQuery, sizeof(sQuery), CTBAN_QUERY_LOG_PERM_TO_TIME_MYSQL, g_sLogTableName, iTime, iTime, sAuthId);
3178 }
3179 }
3180 SQL_TQuery(gH_BanDatabase, DB_Callback_DisconnectAction, sQuery);
3181
3182 ShowActivity2(iClient, "", g_sChatBanner, "Temporary CT Ban", iTarget, iTime);
3183 }
3184}
3185
3186public Action Command_CTBanList(int iClient, int iArgs)
3187{
3188 // console user
3189 if (!iClient)
3190 {
3191 for (int iIndex = ONE; iIndex <= MaxClients; iIndex++)
3192 {
3193 if (IsClientInGame(iIndex))
3194 {
3195 if (GetCTBanStatus(iIndex))
3196 {
3197 if (gA_LocalTimeRemaining[iIndex] <= ZERO)
3198 {
3199 ReplyToCommand(iClient, g_sChatBanner, "Permanent CT Ban", iIndex);
3200 }
3201 else
3202 {
3203 ReplyToCommand(iClient, g_sChatBanner, "Temporary CT Ban", iIndex, gA_LocalTimeRemaining[iIndex]);
3204 }
3205 }
3206 }
3207 }
3208 }
3209 // regular in-game player
3210 else
3211 {
3212 // check if client is allowed to use the command
3213 AdminId clientAdminId = GetUserAdmin(iClient);
3214 char sFlags[MAX_ADMINFLAGS_LENGTH];
3215 GetConVarString(gH_Cvar_CheckCTBans_Flags, sFlags, sizeof(sFlags));
3216 int iAdminFlags = ReadFlagString(sFlags);
3217
3218 #if defined CTBAN_DEBUG
3219 LogMessage("Flag string %s and value %d and client effective %d", sFlags, iAdminFlags, GetAdminFlags(clientAdminId, Access_Effective));
3220 #endif
3221
3222 // length of 0 means they want everyone to have access to this
3223 if (strlen(sFlags) == ZERO)
3224 {
3225 DisplayCTBannedPlayerMenu(iClient, e_CTBanList);
3226 }
3227 // if the player has no admin access
3228 // iAdminFlags bitstring & client's bitstring will leave a logic TRUE if there is overlap
3229 else if (clientAdminId == INVALID_ADMIN_ID || !(iAdminFlags & GetAdminFlags(clientAdminId, Access_Effective)))
3230 {
3231 ReplyToCommand(iClient, g_sChatBanner, "No Access");
3232 }
3233 // they are an admin and they have effective flag access
3234 else
3235 {
3236 DisplayCTBannedPlayerMenu(iClient, e_CTBanList);
3237 }
3238 }
3239
3240 return Plugin_Handled;
3241}
3242
3243public Action Command_IsBanned(int iClient, int iArgs)
3244{
3245 char sTarget[MAX_TARGET_LENGTH];
3246 GetCmdArg(ISBANNED_ARG_TARGET, sTarget, sizeof(sTarget));
3247
3248 char sClientName[MAX_TARGET_LENGTH];
3249 int aiTargetList[MAXPLAYERS];
3250 int iTargetCount;
3251 bool b_tn_is_ml;
3252 iTargetCount = ProcessTargetString(sTarget, iClient, aiTargetList, MAXPLAYERS, COMMAND_FILTER_NO_MULTI | COMMAND_FILTER_NO_IMMUNITY, sClientName, sizeof(sClientName), b_tn_is_ml);
3253 int iTarget = aiTargetList[ZERO];
3254
3255 // Console
3256 if (!iClient)
3257 {
3258 if (!iArgs)
3259 {
3260 ReplyToCommand(iClient, g_sChatBanner, "Command Usage", "sm_isbanned <player>");
3261 }
3262 else
3263 {
3264 if (iTargetCount < ONE)
3265 {
3266 ReplyToTargetError(iClient, iTargetCount);
3267 }
3268 else
3269 {
3270 ProcessIsBannedTarget(iTarget, iClient);
3271 }
3272 }
3273 return Plugin_Handled;
3274 }
3275
3276 // check if client is allowed to use the command
3277 AdminId clientAdminId = GetUserAdmin(iClient);
3278 char sFlags[MAX_ADMINFLAGS_LENGTH];
3279 GetConVarString(gH_Cvar_CheckCTBans_Flags, sFlags, sizeof(sFlags));
3280
3281 int iAdminFlags = ReadFlagString(sFlags);
3282
3283 #if defined CTBAN_DEBUG
3284 LogMessage("Flag string %s and value %d and client effective %d", sFlags, iAdminFlags, GetAdminFlags(clientAdminId, Access_Effective));
3285 #endif
3286
3287 // length of 0 means they want everyone to have access to this
3288 if (strlen(sFlags) == ZERO)
3289 {
3290 if (!iArgs)
3291 {
3292 // automatically target self
3293 ProcessIsBannedTarget(iClient, iClient);
3294 }
3295 else
3296 {
3297 if (iTargetCount < ONE)
3298 {
3299 ReplyToTargetError(iClient, iTargetCount);
3300 }
3301 else
3302 {
3303 ProcessIsBannedTarget(iTarget, iClient);
3304 }
3305 }
3306 }
3307 // if the player has no admin access
3308 // iAdminFlags bitstring & client's bitstring will leave a logic TRUE if there is overlap
3309 else if (clientAdminId == INVALID_ADMIN_ID || !(iAdminFlags & GetAdminFlags(clientAdminId, Access_Effective)))
3310 {
3311 // check if self-targeting allowed
3312 if (GetConVarBool(gH_Cvar_IsBanned_Self))
3313 {
3314 if (!iArgs)
3315 {
3316 // automatically target self
3317 ProcessIsBannedTarget(iClient, iClient);
3318 }
3319 else
3320 {
3321 // check if they target themselves
3322 if (iTargetCount < ONE)
3323 {
3324 ReplyToTargetError(iClient, iTargetCount);
3325 }
3326 else if (iTarget != iClient)
3327 {
3328 ReplyToCommand(iClient, g_sChatBanner, "No Access");
3329 }
3330 // target is the calling client
3331 else
3332 {
3333 ProcessIsBannedTarget(iTarget, iClient);
3334 }
3335 }
3336 }
3337 else
3338 {
3339 ReplyToCommand(iClient, g_sChatBanner, "No Access");
3340 }
3341 }
3342 // they are an admin and they have effective flag access
3343 else
3344 {
3345 if (!iArgs)
3346 {
3347 ReplyToCommand(iClient, g_sChatBanner, "Command Usage", "sm_isbanned <player>");
3348 }
3349 else
3350 {
3351 if (iTargetCount < ONE)
3352 {
3353 ReplyToTargetError(iClient, iTargetCount);
3354 }
3355 else
3356 {
3357 ProcessIsBannedTarget(iTarget, iClient);
3358 }
3359 }
3360 }
3361
3362 return Plugin_Handled;
3363}
3364
3365void ProcessIsBannedTarget(int iTarget, int iCaller)
3366{
3367 #if defined CTBAN_DEBUG
3368 LogMessage("Processing IsBanned on %N by %N", iTarget, iCaller);
3369 #endif
3370
3371 if(iTarget > ZERO && iTarget <= MaxClients && IsClientInGame(iTarget))
3372 {
3373 if (GetCTBanStatus(iTarget, iCaller))
3374 {
3375 // grab perp steam id
3376 char sPerpSteamID[FIELD_AUTHID_MAXLENGTH];
3377 GetClientAuthId(iTarget, AuthId_Steam2, sPerpSteamID, sizeof(sPerpSteamID));
3378
3379 char sQuery[QUERY_MAXLENGTH];
3380 Format(sQuery, sizeof(sQuery), CTBAN_QUERY_LOG_ISBANNED, g_sLogTableName, sPerpSteamID);
3381
3382 #if defined CTBAN_DEBUG
3383 LogMessage("isbanned query: %s", sQuery);
3384 #endif
3385
3386 Handle hDataPack = CreateDataPack();
3387 // perp SteamID
3388 WritePackString(hDataPack, sPerpSteamID);
3389 // current client who asked for isbanned info
3390 WritePackCell(hDataPack, iCaller);
3391 // target index
3392 WritePackCell(hDataPack, iTarget);
3393
3394 SQL_TQuery(gH_BanDatabase, DB_Callback_IsBanned, sQuery, hDataPack);
3395 }
3396 else
3397 {
3398 if (iCaller != CALLER_NATIVE)
3399 {
3400 ReplyToCommand(iCaller, g_sChatBanner, "Not CT Banned", iTarget);
3401 }
3402 else
3403 {
3404 ThrowNativeError(SP_ERROR_NATIVE, g_sChatBanner, "Not CT Banned", iTarget);
3405 }
3406 }
3407 }
3408 else
3409 {
3410 if (iCaller != CALLER_NATIVE)
3411 {
3412 ReplyToCommand(iCaller, g_sChatBanner, "Unable to target");
3413 }
3414 else
3415 {
3416 ThrowNativeError(SP_ERROR_NATIVE, g_sChatBanner, "Unable to target");
3417 }
3418 }
3419}
3420
3421public void DB_Callback_IsBanned(Handle hOwner, Handle hCallback, const char[] sError, any hDataPack)
3422{
3423 if (hCallback == INVALID_HANDLE)
3424 {
3425 LogError("Error in IsBanned query: %s", sError);
3426 CloseHandle(hDataPack);
3427 }
3428 else
3429 {
3430 ResetPack(hDataPack);
3431 char sPerpAuthID[FIELD_AUTHID_MAXLENGTH];
3432 ReadPackString(hDataPack, sPerpAuthID, sizeof(sPerpAuthID));
3433 int iCaller = ReadPackCell(hDataPack);
3434 int iTarget = ReadPackCell(hDataPack);
3435 CloseHandle(hDataPack);
3436
3437 int iRowCount = SQL_GetRowCount(hCallback);
3438 if (iRowCount > ONE || iRowCount < ZERO)
3439 {
3440 LogError("%d rows returned on LIMIT 1 query: %s", iRowCount, sError);
3441 }
3442 else if (!iRowCount)
3443 {
3444 #if defined CTBAN_DEBUG
3445 LogMessage("Row count is 0 for IsBanned Query!");
3446 #endif
3447
3448 if (iCaller == CALLER_NATIVE)
3449 {
3450 // Have to use incomplete information because the row is missing from the database table
3451 Call_StartForward(g_hFrwd_CTBanInfo);
3452 Call_PushCell(false);
3453 Call_PushCell(iTarget);
3454 Call_PushCell(gA_LocalTimeRemaining[iTarget]);
3455 Call_PushCell(CALLER_NATIVE);
3456 Call_PushString("Invalid");
3457 Call_PushString("Invalid");
3458 Call_Finish();
3459 }
3460 else if (gA_LocalTimeRemaining[iTarget] <= ZERO)
3461 {
3462 if (!iCaller)
3463 {
3464 PrintToServer(g_sChatBanner, "Permanent CT Ban", iTarget);
3465 }
3466 else
3467 {
3468 CPrintToChat(iCaller, g_sChatBanner, "Permanent CT Ban", iTarget);
3469 }
3470 }
3471 else
3472 {
3473 if (!iCaller)
3474 {
3475 PrintToServer(g_sChatBanner, "Temporary CT Ban", iTarget, gA_LocalTimeRemaining[iTarget]);
3476 }
3477 else
3478 {
3479 CPrintToChat(iCaller, g_sChatBanner, "Temporary CT Ban", iTarget, gA_LocalTimeRemaining[iTarget]);
3480 }
3481 }
3482 }
3483 // Rows are exactly 1
3484 else
3485 {
3486 SQL_FetchRow(hCallback);
3487 int iTimeStamp = SQL_FetchInt(hCallback, ISBANNED_CB_FIELD_TIMESTAMP);
3488 char sAdminName[FIELD_NAME_MAXLENGTH];
3489 SQL_FetchString(hCallback, ISBANNED_CB_FIELD_ADMINNAME, sAdminName, sizeof(sAdminName));
3490 char sReason[FIELD_REASON_MAXLENGTH];
3491 SQL_FetchString(hCallback, ISBANNED_CB_FIELD_REASON, sReason, sizeof(sReason));
3492 #if defined CTBAN_DEBUG
3493 LogMessage("SQL ISBanned: admin %s banned with timestamp %d for reason %s", sAdminName, iTimeStamp, sReason);
3494 #endif
3495
3496 char sTimeBanned[MAX_TIME_INFO_STR_LENGTH];
3497 FormatTime(sTimeBanned, sizeof(sTimeBanned), NULL_STRING, iTimeStamp);
3498
3499 #if defined CTBAN_DEBUG
3500 LogMessage("target %N, admin banning %s, when banned %s, timeleft %d", iTarget, sAdminName, sTimeBanned, gA_LocalTimeRemaining[iTarget]);
3501 #endif
3502
3503 // check if we need to fire a forward from a native call
3504 if (iCaller == CALLER_NATIVE)
3505 {
3506 Call_StartForward(g_hFrwd_CTBanInfo);
3507 Call_PushCell(true);
3508 Call_PushCell(iTarget);
3509 Call_PushCell(gA_LocalTimeRemaining[iTarget]);
3510 Call_PushCell(iTimeStamp);
3511 Call_PushString(sAdminName);
3512 Call_PushString(sReason);
3513 Call_Finish();
3514 }
3515 // find the time if any
3516 else if (gA_LocalTimeRemaining[iTarget] <= ZERO)
3517 {
3518 if (!iCaller)
3519 {
3520 PrintToServer(g_sChatBanner, "IsBanned Permanent", iTarget, sAdminName, sTimeBanned, sReason);
3521 }
3522 else
3523 {
3524 CPrintToChat(iCaller, g_sChatBanner, "IsBanned Permanent", iTarget, sAdminName, sTimeBanned, sReason);
3525 }
3526 }
3527 else
3528 {
3529 if (!iCaller)
3530 {
3531 PrintToServer(g_sChatBanner, "IsBanned Temporary", iTarget, gA_LocalTimeRemaining[iTarget], sAdminName, sTimeBanned, sReason);
3532 }
3533 else
3534 {
3535 CPrintToChat(iCaller, g_sChatBanner, "IsBanned Temporary", iTarget, gA_LocalTimeRemaining[iTarget], sAdminName, sTimeBanned, sReason);
3536 }
3537 }
3538 }
3539 }
3540}
3541
3542public Action Command_Offline_IsBanned(int iClient, int iArgs)
3543{
3544 char sPerpSteamID[FIELD_AUTHID_MAXLENGTH];
3545 GetCmdArgString(sPerpSteamID, sizeof(sPerpSteamID));
3546 TrimString(sPerpSteamID);
3547
3548 if (IsAuthIdConnected(sPerpSteamID))
3549 {
3550 ReplyToCommand(iClient, g_sChatBanner, "Unable to target");
3551 }
3552 else
3553 {
3554 ProcessIsBannedOffline(iClient, sPerpSteamID);
3555 }
3556
3557 return Plugin_Handled;
3558}
3559
3560void ProcessIsBannedOffline(int iCaller, char[] sPerpAuthID)
3561{
3562 char sEscapedPerpSteamID[MAX_SAFE_ESCAPE_QUERY(FIELD_NAME_MAXLENGTH)];
3563 SQL_EscapeString(gH_BanDatabase, sPerpAuthID, sEscapedPerpSteamID, sizeof(sEscapedPerpSteamID));
3564
3565 char sQuery[QUERY_MAXLENGTH];
3566 Format(sQuery, sizeof(sQuery), CTBAN_QUERY_LOG_ISBANNED_OFFLINE, g_sLogTableName, sEscapedPerpSteamID);
3567
3568 #if defined CTBAN_DEBUG
3569 LogMessage("offline isbanned query: %s", sQuery);
3570 #endif
3571
3572 Handle hDataPack = CreateDataPack();
3573 // perp SteamID
3574 WritePackString(hDataPack, sPerpAuthID);
3575 // current client who asked for isbanned info
3576 WritePackCell(hDataPack, iCaller);
3577
3578 SQL_TQuery(gH_BanDatabase, DB_Callback_Offline_IsBanned, sQuery, hDataPack);
3579}
3580
3581public void DB_Callback_Offline_IsBanned(Handle hOwner, Handle hCallback, const char[] sError, any hOfflineIsBannedPack)
3582{
3583 if (hCallback == INVALID_HANDLE)
3584 {
3585 LogError("Error in Offline IsBanned query: %s", sError);
3586 }
3587 else
3588 {
3589 ResetPack(hOfflineIsBannedPack);
3590 char sPerpAuthID[FIELD_AUTHID_MAXLENGTH];
3591 ReadPackString(hOfflineIsBannedPack, sPerpAuthID, sizeof(sPerpAuthID));
3592 int iClient = ReadPackCell(hOfflineIsBannedPack);
3593 CloseHandle(hOfflineIsBannedPack);
3594
3595 int iRowCount = SQL_GetRowCount(hCallback);
3596 if (iRowCount != ONE)
3597 {
3598 if (iClient == CALLER_NATIVE)
3599 {
3600 Call_StartForward(g_hFrwd_CTBanInfoOffline);
3601 Call_PushCell(false);
3602 Call_PushString(sPerpAuthID);
3603 Call_PushCell(CALLER_NATIVE);
3604 Call_PushCell(CALLER_NATIVE);
3605 Call_PushString("Invalid");
3606 Call_PushString("Invalid");
3607 Call_PushString("Invalid");
3608 Call_Finish();
3609 }
3610 else if (!iClient)
3611 {
3612 PrintToServer(g_sChatBanner, "No matching client");
3613 }
3614 else
3615 {
3616 CPrintToChat(iClient, g_sChatBanner, "No matching client");
3617 }
3618 }
3619 else
3620 {
3621 SQL_FetchRow(hCallback);
3622 int timestamp = SQL_FetchInt(hCallback, ISBANNED_OFF_CB_FIELD_TIMESTAMP);
3623 char sAdminName[FIELD_NAME_MAXLENGTH];
3624 SQL_FetchString(hCallback, ISBANNED_OFF_CB_FIELD_ADMINNAME, sAdminName, sizeof(sAdminName));
3625 char sReason[FIELD_REASON_MAXLENGTH];
3626 SQL_FetchString(hCallback, ISBANNED_OFF_CB_FIELD_REASON, sReason, sizeof(sReason));
3627 int timeleft = SQL_FetchInt(hCallback, ISBANNED_OFF_CB_FIELD_TIMELEFT);
3628 char sPerpName[FIELD_NAME_MAXLENGTH];
3629 SQL_FetchString(hCallback, ISBANNED_OFF_CB_FIELD_PERPNAME, sPerpName, sizeof(sPerpName));
3630
3631 char sTimeBanned[MAX_TIME_INFO_STR_LENGTH];
3632 FormatTime(sTimeBanned, sizeof(sTimeBanned), NULL_STRING, timestamp);
3633
3634 #if defined CTBAN_DEBUG
3635 LogMessage("target name %s, admin banning %s, when banned %s, timeleft %d", sPerpName, sAdminName, sTimeBanned, timeleft);
3636 #endif
3637
3638 if (iClient == CALLER_NATIVE)
3639 {
3640 Call_StartForward(g_hFrwd_CTBanInfoOffline);
3641 Call_PushCell(true);
3642 Call_PushString(sPerpAuthID);
3643 Call_PushCell(timeleft);
3644 Call_PushCell(timestamp);
3645 Call_PushString(sAdminName);
3646 Call_PushString(sReason);
3647 Call_PushString(sPerpName);
3648 Call_Finish();
3649 }
3650 else if (timeleft <= ZERO)
3651 {
3652 if (!iClient)
3653 {
3654 PrintToServer(g_sChatBanner, "IsBanned Permanent String Name", sPerpName, sAdminName, sTimeBanned, sReason);
3655 }
3656 else
3657 {
3658 CPrintToChat(iClient, g_sChatBanner, "IsBanned Permanent String Name", sPerpName, sAdminName, sTimeBanned, sReason);
3659 }
3660 }
3661 else
3662 {
3663 if (!iClient)
3664 {
3665 PrintToServer(g_sChatBanner, "IsBanned Temporary String Name", sPerpName, timeleft, sAdminName, sTimeBanned, sReason);
3666 }
3667 else
3668 {
3669 CPrintToChat(iClient, g_sChatBanner, "IsBanned Temporary String Name", sPerpName, timeleft, sAdminName, sTimeBanned, sReason);
3670 }
3671 }
3672 }
3673 }
3674}
3675
3676public Action Command_CheckJoin(int iClient, const char[] sCommand, int iArgs)
3677{
3678 // Check to see if we should continue (not a listen server, is in game, not a bot, if cookies are cached, and we're enabled)
3679 if(!iClient || !IsClientInGame(iClient) || IsFakeClient(iClient) || !AreClientCookiesCached(iClient))
3680 {
3681 return Plugin_Continue;
3682 }
3683
3684 // Get the target team
3685 char sJoinTeamString[MAX_JOINTEAM_ARG_LENGTH];
3686 GetCmdArg(JOINTEAM_ARG_TEAM_STRING, sJoinTeamString, sizeof(sJoinTeamString));
3687 int iTargetTeam = StringToInt(sJoinTeamString);
3688
3689 int iBanStatus = GetCTBanStatus(iClient);
3690
3691 // check for an active ban to send a message
3692 if ((iTargetTeam == CS_TEAM_SPECTATOR || iTargetTeam == CS_TEAM_T) && iBanStatus)
3693 {
3694 // display them a message about the ban
3695 int iTimeBanned = GetClientCookieTime(iClient, g_CT_Cookie);
3696 char sTimeBanned[MAX_TIME_INFO_STR_LENGTH];
3697 FormatTime(sTimeBanned, sizeof(sTimeBanned), NULL_STRING, iTimeBanned);
3698 char sJoinBanMsg[MAX_JOIN_BAN_MSG_LENGTH];
3699 GetConVarString(gH_Cvar_JoinBanMessage, sJoinBanMsg, sizeof(sJoinBanMsg));
3700 PrintHintText(iClient, "%t", "Last CT Banned On", sTimeBanned, sJoinBanMsg);
3701
3702 if (GetConVarBool(gH_Cvar_IsBanned_Self))
3703 {
3704 ProcessIsBannedTarget(iClient, iClient);
3705 }
3706 }
3707 // otherwise they joined CT or auto-select and are banned
3708 else if (iBanStatus)
3709 {
3710 if(strcmp(gS_SoundPath, ""))
3711 {
3712 char sPlayCommand[PLATFORM_MAX_PATH + PLAY_COMMAND_STRING_LENGTH];
3713 Format(sPlayCommand, sizeof(sPlayCommand), "%s%s", PLAY_COMMAND_STRING, gS_SoundPath);
3714 ClientCommand(iClient, sPlayCommand);
3715 }
3716 CPrintToChat(iClient, g_sChatBanner, "Enforcing CT Ban");
3717
3718 // if they are already on the Terrorist team then they don't need to pick anything again
3719 if (GetClientTeam(iClient) != CS_TEAM_T)
3720 {
3721 UTIL_TeamMenu(iClient);
3722 }
3723
3724 return Plugin_Stop;
3725 }
3726
3727 return Plugin_Continue;
3728}
3729
3730// This helper procedure will re-display the team join menu
3731// and is equivalent to what ClientCommand(client, "chooseteam") did in the past
3732void UTIL_TeamMenu(int iClient)
3733{
3734 int aiClients[ONE];
3735 Handle hBfWritePack;
3736 aiClients[ZERO] = iClient;
3737 hBfWritePack = StartMessage("VGUIMenu", aiClients, ONE);
3738
3739 if (GetUserMessageType() == UM_Protobuf)
3740 {
3741 PbSetString(hBfWritePack, "name", "team");
3742 PbSetBool(hBfWritePack, "show", true);
3743 }
3744 else
3745 {
3746 BfWriteString(hBfWritePack, "team"); // panel name
3747 BfWriteByte(hBfWritePack, ONE); // bShow
3748 BfWriteByte(hBfWritePack, ZERO); // count
3749 }
3750
3751 EndMessage();
3752}
3753
3754// figure out if we can use the handy native SetAuthIdCookie
3755bool IsSetAuthIdNativePresent()
3756{
3757 if (GetFeatureStatus(FeatureType_Native, "SetAuthIdCookie") == FeatureStatus_Available)
3758 {
3759 return true;
3760 }
3761 return false;
3762}
3763
3764int GetCTBanStatus(int iClient, int iCaller = CALLER_DO_NOT_REPLY)
3765{
3766 int iCTBanStatus = ZERO;
3767
3768 if (AreClientCookiesCached(iClient))
3769 {
3770 char sCookie[MAX_COOKIE_STR_LENGTH];
3771 GetClientCookie(iClient, g_CT_Cookie, sCookie, sizeof(sCookie));
3772 iCTBanStatus = StringToInt(sCookie);
3773 }
3774 else
3775 {
3776 if (iCaller >= ZERO)
3777 {
3778 ReplyToCommand(iCaller, g_sChatBanner, "Cookie Status Unavailable");
3779 }
3780 }
3781
3782 return iCTBanStatus;
3783}
3784
3785void EnforceCTBan(int iClient)
3786{
3787 if (IsPlayerAlive(iClient))
3788 {
3789 // strip their weapons so they cannot gunplant after death
3790 StripAllWeapons(iClient);
3791
3792 ForcePlayerSuicide(iClient);
3793 }
3794
3795 ChangeClientTeam(iClient, CS_TEAM_T);
3796
3797 if (GetConVarBool(gH_Cvar_Respawn))
3798 {
3799 CS_RespawnPlayer(iClient);
3800 }
3801
3802 CPrintToChat(iClient, g_sChatBanner, "Enforcing CT Ban");
3803}
3804
3805#if !defined _Hosties_Included_
3806 // From hosties.inc on Beta branch (20 Aug 2017)
3807 stock void StripAllWeapons(int iClient)
3808 {
3809 int iWeaponIndex = INVALID_WEAPON;
3810 for (int iLoopIndex = CS_SLOT_PRIMARY; iLoopIndex < CS_SLOT_GRENADE + ONE; iLoopIndex++)
3811 {
3812 iWeaponIndex = INVALID_WEAPON;
3813 while ((iWeaponIndex = GetPlayerWeaponSlot(iClient, iLoopIndex)) != INVALID_WEAPON)
3814 {
3815 RemovePlayerItem(iClient, iWeaponIndex);
3816 AcceptEntityInput(iWeaponIndex, "Kill");
3817 }
3818 }
3819 }
3820#endif
3821
3822#if !defined _CTBan_Included_
3823 stock int IsAuthIdConnected(char[] sAuthID)
3824 {
3825 char sIndexAuthID[FIELD_AUTHID_MAXLENGTH];
3826 for (int iIndex = ONE; iIndex <= MaxClients; iIndex++)
3827 {
3828 if (IsClientInGame(iIndex))
3829 {
3830 GetClientAuthId(iIndex, AuthId_Steam2, sIndexAuthID, sizeof(sIndexAuthID));
3831 if (StrEqual(sAuthID, sIndexAuthID))
3832 {
3833 return iIndex;
3834 }
3835 }
3836 }
3837
3838 return ZERO;
3839 }
3840
3841 stock void ParseCTBanReasonsFile(Handle hReasonsArray)
3842 {
3843 ClearArray(hReasonsArray);
3844
3845 char sPathReasons[PLATFORM_MAX_PATH];
3846 BuildPath(Path_SM, sPathReasons, sizeof(sPathReasons), "configs/ctban_reasons.ini");
3847 Handle hReasonsFile = OpenFile(sPathReasons, "r");
3848
3849 if (hReasonsFile != null)
3850 {
3851 char sReasonsLine[FIELD_REASON_MAXLENGTH];
3852
3853 while (ReadFileLine(hReasonsFile, sReasonsLine, sizeof(sReasonsLine)))
3854 {
3855 PushArrayString(hReasonsArray, sReasonsLine);
3856 }
3857 }
3858
3859 CloseHandle(hReasonsFile);
3860 }
3861
3862 stock Handle ParseCTBanLengthsFile(Handle hKeyValues)
3863 {
3864 if (hKeyValues != INVALID_HANDLE)
3865 {
3866 CloseHandle(hKeyValues);
3867 }
3868
3869 hKeyValues = CreateKeyValues("length");
3870
3871 char sPathLengths[PLATFORM_MAX_PATH];
3872 BuildPath(Path_SM, sPathLengths, sizeof(sPathLengths), "configs/ctban_times.ini");
3873
3874 if (FileToKeyValues(hKeyValues, sPathLengths))
3875 {
3876 KvRewind(hKeyValues);
3877 }
3878 else
3879 {
3880 CloseHandle(hKeyValues);
3881 return INVALID_HANDLE;
3882 }
3883
3884 return hKeyValues;
3885 }
3886
3887 stock void SetCTBanChatBanner(EngineVersion e_EngineVersion, char sChatBanner[MAX_CHAT_BANNER_LENGTH])
3888 {
3889 switch (e_EngineVersion)
3890 {
3891 case Engine_CSS, Engine_TF2:
3892 {
3893 sChatBanner = "[\x0799CCFFCTBAN\x01] \x07FFD700%t";
3894 }
3895 case Engine_CSGO:
3896 {
3897 sChatBanner = "[\x0BCTBAN\x01] \x10%t";
3898 }
3899 default:
3900 {
3901 SetFailState("Game engine is not supported.");
3902 }
3903 }
3904 }
3905#endif
3906
3907/*
3908 [CS:S/CS:GO] CT Bans
3909 by: databomb
3910*/