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