· 8 years ago · Mar 31, 2018, 07:40 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,a
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17 ***************************************************************************
18
19 Description:
20 Allows admins to restrict access to the CT team from those who violate the server's rules. Designed for specific usage in Jailbreak environments.
21
22 Features:
23 - CT Bans are stored in the ClientPrefs database and survive map changes, re-joins, and server crashes.
24 - The Rage Ban feature allows admins to CT ban rage quitters who break the server's rules and then quickly disconnect.
25 - You may give a timed CT ban which will work based on in minutes spent alive (so idlers in spectate or those who suicide at the beginning of the round will not be working toward an unban.)
26 - The timed CT bans are stored in a SQL table for stateful access.
27 - The plugin logs CT ban to a SQL table in addition to your regular SM logs.
28 - Re-displays the team selection screen after an improper selection was made.
29 - SM Menu integration for the rageban and ctban commands.
30 - Displays helpful message to users who are CT banned when they join the server.
31 - SM Translations support.
32 - Custom reasons permitted (configs/ctban_reasons.ini).
33 - Custom lengths permitted (configs/ctban_times.ini).
34
35 Installation:
36 Place the ctban.phrases.txt file in your addons/sourcemod/translations directory.
37 Place the sm_ctban.smx file in your addons/sourcemod/plugins directory.
38 Check your logs/server-console after the initial load for any SQL errors. If you have any SQL errors check your addons/sourcemod/configs/databases.cfg file and verify you can connect using the drivers you have specified.
39 Upgrade: Delete cfg/sourcemod/ctban.cfg and re-configure convars after the file is re-created.
40 Optional: Generate custom reasons list by creating a simple text file (addons/sourcemod/configs/ctban_reasons.ini) with 1 reason per line.
41
42 Command Usage:
43
44 sm_ctban <player> <time> <optional: reason>
45 Bans the selected player from joining the CT team.
46
47 sm_removectban <player> | sm_unctban <player>
48 Removes the CT ban on the selected player.
49
50 sm_isbanned <player>
51 Reports back the status of the current player's CT ban and the time remaining on the ban, if any.
52
53 sm_rageban
54 Brings up a menu so you may choose a recently disconnected player to permanently CT ban.
55
56 sm_ctban_offline <steamid>
57 Bans the given Steam Id from playing on the CT team.
58
59 sm_removectban_offline <steamid> | sm_unctban_offline <steamid>
60 Unbans the given Steam Id from the CT team.
61
62 sm_reset_ctban_cookies <'force'>
63 Resets the entire CTBan cookie database.
64
65 sm_forcect <player>
66 Overrides any CTBans and swaps a player to CT team.
67
68 sm_unforcect <player>
69 Removes overrides and moves player to T team.
70
71 sm_isbanned_offline <steamid>
72 Reports back the status of the target Steam Id from the ban database.
73
74 sm_change_ctban_time <player> <time>
75 Changes an existing CTBan to the new time specified. 0 would be permanently CTBan.
76
77 sm_ctbanlist
78 Displays a menu of active players who are CT Banned.
79
80 Settings:
81 sm_ctban_soundfile, <path>: The path to the soundfile to play when denying a team-change request. Set to "" to disable.
82 sm_ctban_joinbanmsg, <message>: This message is appended to a time-stamp when a CT banned user joins the server.
83 sm_ctban_table_prefix, <prefix>: This prefix will be added in front of the table names.
84 sm_ctban_database_driver, <driver>: This specifies which driver to use from database.cfg
85 sm_ctban_force_reason, [0,1]: Specifies whether a reason is required for the CT Ban command.
86 sm_ctban_checkctbans_adminflags, [a-z]: Specifies the admin flag levels that may use the !ctbanlist and !isbanned command targeting anyone. Blank allows all players access on everyone.
87 sm_ctban_isbanned_selftarget, [0,1]: Specifies whether a non-admin can target themselves using the !isbanned command.
88 sm_ctban_respawn, [0,1]: Specifies whether to respawn players after team changes.
89
90 Special Thanks (Development):
91 Azelphur for snippets of cross-mod code.
92 Kigen for the idea of CT banning based on time spent alive.
93 oaaron99 for the idea of smart !ctban menu re-directs.
94 Bara for include file ideas and lengths code.
95
96 Future Considerations:
97 Using API-- Steam Group CTBans
98 Using API-- New Admin Level and Command for CT Banning for Only Small Durations
99
100 Change Log:
101 2.0.3 Adds !rageban console user support. Fixed bug where !rageban was not permanent. Fixed bug with custom times (configs/ctban_times.ini) not displaying menu options correctly.
102 Adds multi-targeting filters for other admin commands: @ctban @!ctban and @noctbans (@noctbans specifies players who have never had a CT Ban).
103 2.0.2 Adds SQLite support. Updated include file: Adds more intelligent #tryinclude and pre-compile directives.
104 Alerts admins if someone is swapped to CT without !forcect. Added custom times options (configs/ctban_times.ini).
105 Times file should be formatted as a Key Values file with each section having the number of minutes and a description such as: "90" "1 Hour 30 Minutes"
106 2.0.1 Bug fixes in UnForceCT, ForceCT, and OnClientAuthorized which were each generating errors.
107 2.0.0 Ported to the new syntax. Translation file updated. CS:GO Fixes bug where mp_force_pick_time could assign a banned player to CT. Made !ctban open menus if more info is needed.
108 CS:GO Fixes incompatibility with Zephyrus's Team Limit Bypass plugin. Adds spawn check to verify CTBans. Added !forcect/!unforcect to override CTBan and swap players.
109 Allows custom reasons (configs/ctban_reasons.ini). Allows non-admins to use !isbanned. Added command to reset all CT Ban cookies. Added Player Commands menu for !unctban.
110 Adds CT Ban to !admin Player Commands menu. Allowed fallback for !isbanned to return ban info even if database log entries were missing. Added !ctbanlist command.
111 Added CT Ban reason to !ctban chat output where possible. Changed from [SM] to [CTBAN] chat tag and added colors. Removing compile option USESQL (Now Always Uses SQL).
112 Added !isbanned_offline to find CT Ban info of offline players. !ctban_offline and !unctban_offline now update the log database records.
113 Added convar sm_ctban_respawn to allow respawns after team swaps due to !ctban or !forcect. Added !change_ctban_time command to edit the time remaining on CTBans.
114 Added API (ctban.inc) for 3rd-party plugin interfaces. The convar sm_ctban_enable is being removed (disable the plugin to disable functionality).
115 Upgraded database log table to include an auto incrementing primary key (ban_id) -- automatically upgrades from tables.
116 Added check for enforcing CTBans if the plugin is loaded late.
117 1.6.2 Translation file updated. Added admin, time, reason information for !isbanned. Show !rageban results in chat to players. Added ConVar for forcing !ctban reason.
118 1.6.1.4 Fixed bug preventing console CT bans (thanks Kailo!)
119 1.6.1.3 Fixed bug with EscapeString function which caused query failures
120 1.6.1.2 Fixed SQL Injection vulnerability
121 1.6.1.1 Fixed problem in UTIL_TeamMenu()
122 1.6.1 Support for new SM1.4 natives, Added config file generation
123 1.6.0 Added support for new SM1.4 natives
124 1.5.0 Initial public release
125 1.4.4 Stable internal build
126*/
127
128// Compilation Settings
129//#define CTBAN_DEBUG
130
131#define PLUGIN_VERSION "2.0.3"
132
133#include <sourcemod>
134#include <clientprefs>
135#include <sdktools>
136#include <adminmenu>
137#include <cstrike>
138#include <db>
139
140#tryinclude <hosties>
141#tryinclude <ctban>
142
143#if !defined _CTBan_Included_
144
145 // Common constant verifications
146 #if !defined INVALID_WEAPON
147 #define INVALID_WEAPON -1
148 #else
149 #assert INVALID_WEAPON == -1
150 #endif
151 #if !defined ZERO
152 #define ZERO 0
153 #else
154 #assert ZERO == 0
155 #endif
156 #if !defined ONE
157 #define ONE 1
158 #else
159 #assert ONE == 1
160 #endif
161 #if !defined TWO 2
162 #define TWO 2
163 #else
164 #assert TWO == 2
165 #endif
166 #if !defined THREE
167 #define THREE 3
168 #else
169 #assert THREE == 3
170 #endif
171 #if !defined FOUR
172 #define FOUR 4
173 #else
174 #assert FOUR == 4
175 #endif
176 #if !defined FIVE
177 #define FIVE 5
178 #else
179 #assert FIVE == 5
180 #endif
181 #if !defined SIX
182 #define SIX 6
183 #else
184 #assert SIX == 6
185 #endif
186 #if !defined SEVEN
187 #define SEVEN 7
188 #else
189 #assert SEVEN == 7
190 #endif
191
192 // General constants
193 #define VALUE_NOT_FOUND_IN_ARRAY -1
194 #define SUBSTRING_NOT_FOUND -1
195 #define RAGEBAN_ADMIN_LEVEL ADMFLAG_SLAY
196 #define CTBAN_ADMIN_LEVEL ADMFLAG_SLAY
197 #define UNCTBAN_ADMIN_LEVEL ADMFLAG_SLAY
198 #define FORCECT_ADMIN_LEVEL ADMFLAG_SLAY
199 #define UNFORCECT_ADMIN_LEVEL ADMFLAG_SLAY
200 #define JOINFAILREASON_ONECHANGE 0
201 #define MENUCHOICE_USERID 0
202 #define MENUCHOICE_TIME 1
203 #define CALLER_NATIVE -2
204 #define COOKIE_BANNED_STRING "1"
205 #define COOKIE_UNBANNED_STRING "0"
206 #define ARG_ZERO_GET_COMMAND_NAME 0
207 #define FORCECT_ARG_TARGET 1
208 #define UNFORCECT_ARG_TARGET 1
209 #define ISBANNED_ARG_TARGET 1
210 #define CTBAN_ARG_PLAYER 1
211 #define CTBAN_ARG_TIME 2
212 #define CTBAN_ARG_REASON 3
213 #define CTBAN_NO_REASON_GIVEN -1
214 #define CTBAN_PERM_BAN_LENGTH 0
215 #define RAGEBAN_ARG_CONSOLE_TARGET 1
216 #define UNCTBAN_ARG_TARGET 1
217 #define CHANGE_TIME_ARG_TARGET 1
218 #define CHANGE_TIME_ARG_TIME 2
219 #define JOINTEAM_ARG_TEAM_STRING 1
220 #define CLIENT_DISCONNECT_CB_FIELD_TIMELEFT 0
221 #define FIND_COOKIE_CB_FIELD_COOKIE_ID 0
222 #define CLIENT_AUTHED_CB_FIELD_TIMELEFT 0
223 #define ISBANNED_CB_FIELD_TIMESTAMP 0
224 #define ISBANNED_CB_FIELD_ADMINNAME 1
225 #define ISBANNED_CB_FIELD_REASON 2
226 #define ISBANNED_OFF_CB_FIELD_TIMESTAMP 0
227 #define ISBANNED_OFF_CB_FIELD_ADMINNAME 1
228 #define ISBANNED_OFF_CB_FIELD_REASON 2
229 #define ISBANNED_OFF_CB_FIELD_TIMELEFT 3
230 #define ISBANNED_OFF_CB_FIELD_PERPNAME 4
231 #define NATIVE_ISBANNED_CELL_CLIENT 1
232 #define NATIVE_GET_TIMELEFT_CELL_CLIENT 1
233 #define NATIVE_GET_OVERRIDE_CELL_CLIENT 1
234 #define NATIVE_GETBANINFO_CELL_CLIENT 1
235 #define NATIVE_GETBANINFO_OFF_STR_AUTHID 1
236 #define NATIVE_CTBAN_CELL_CLIENT 1
237 #define NATIVE_CTBAN_CELL_TIME 2
238 #define NATIVE_CTBAN_CELL_ADMIN 3
239 #define NATIVE_CTBAN_STR_REASON 4
240 #define NATIVE_CTBAN_OFF_STR_AUTHID 1
241 #define NATIVE_CHANGE_TIME_CELL_CLIENT 1
242 #define NATIVE_CHANGE_TIME_CELL_TIME 2
243 #define NATIVE_CHANGE_TIME_CELL_ADMIN 3
244 #define NATIVE_UNBAN_CELL_CLIENT 1
245 #define NATIVE_UNBAN_CELL_ADMIN 2
246 #define NATIVE_UNBAN_OFF_STR_AUTHID 1
247 #define NATIVE_FORCECT_CELL_CLIENT 1
248 #define NATIVE_FORCECT_CELL_ADMIN 2
249 #define NATIVE_UNFORCECT_CELL_CLIENT 1
250 #define NATIVE_UNFORCECT_CELL_ADMIN 2
251 #define NATIVE_MIN_AUTHID_LENGTH 3
252 #define FIELD_AUTHID_MAXLENGTH 22
253 #define FIELD_NAME_MAXLENGTH 32
254 #define FIELD_REASON_MAXLENGTH 200
255 #define QUERY_MAXLENGTH 350
256 #define COOKIE_INIT_CHECK_TIME 0.0
257 #define COOKIE_RESCAN_TIME 5.0
258 #define DELAY_ENFORCEMENT_TIME 1.8
259 #define AUTH_RESCAN_TIME 4.0
260 #define DECREMENT_TIMEBAN_INTERVAL 60.0
261 #define PLAY_COMMAND_STRING "play "
262 #define PLAY_COMMAND_STRING_LENGTH 5
263 #define CSGO_MAX_PAGE_MENU_ITEMS 6
264 #define CSS_MAX_PAGE_MENU_ITEMS 7
265 #define CTBAN_COMMAND "sm_ctban"
266 #define REMOVECTBAN_COMMAND "sm_removectban"
267 #define RAGEBAN_COMMAND "sm_rageban"
268 #define FORCECT_COMMAND "sm_forcect"
269 #define UNFORCECT_COMMAND "sm_unforcect"
270 #define MAX_UNBAN_CMD_LENGTH 16
271 #define MAX_TABLE_LENGTH 32
272 #define MAX_DEFAULT_TABLE_LENGTH 12
273 #define MAX_CHAT_BANNER_LENGTH 36
274 #define MAX_RESET_ARG_LENGTH 10
275 #define MAX_USERID_LENGTH 32
276 #define MAX_COOKIE_STR_LENGTH 7
277 #define MAX_JOINTEAM_ARG_LENGTH 5
278 #define MAX_TIME_ARG_LENGTH 32
279 #define MAX_TIME_INFO_STR_LENGTH 150
280 #define MAX_JOIN_BAN_MSG_LENGTH 100
281 #define MAX_ADMINFLAGS_LENGTH 27
282 #define MAX_REASON_MENU_CHOICE_LENGTH 10
283 #define MAX_MENU_INT_CHOICE_LENGTH 4
284 #define MAX_DATABASE_ID_LENGTH 7
285 #define CTBAN_ADMIN_IS_CONSOLE 0
286 #define CONSOLE_USER_NAME "Console"
287 #define CONSOLE_AUTHID "STEAM_0:1:1"
288 #define RAGEBAN_LOG_REASON "Rage ban"
289 #define OFFLINE_NAME_UNAVAILBLE "Unavailable"
290 #define REASON_OFFLINECTBAN "Offline AuthId Ban"
291 #define CALLER_DO_NOT_REPLY -1
292
293 // Pre-processor macros
294 #define MAX_SAFE_ESCAPE_QUERY(%1) (TWO*(%1)+ONE)
295
296#endif
297
298// SQL Queries
299#define CTBAN_QUERY_CP_FIND_COOKIE_ID "SELECT id FROM sm_cookies WHERE name = 'Banned_From_CT'"
300#define CTBAN_QUERY_CP_SELECT_BAN_COOKIE "SELECT value FROM sm_cookie_cache WHERE player = '%s' and cookie_id = '%i'"
301#define CTBAN_QUERY_CP_RESET_COOKIES "UPDATE sm_cookie_cache SET value = '' WHERE cookie_id = '%i'"
302
303#define CTBAN_QUERY_TIME_CREATE "CREATE TABLE IF NOT EXISTS %s (steamid VARCHAR(%d), ctbantime INT(16), PRIMARY KEY (steamid))"
304#define CTBAN_QUERY_TIME_SELECT_BANTIME "SELECT ctbantime FROM %s WHERE steamid = '%s'"
305#define CTBAN_QUERY_TIME_INSERT_SQLITE "INSERT OR REPLACE INTO %s (steamid, ctbantime) VALUES ('%s', %d)"
306#define CTBAN_QUERY_TIME_INSERT_MYSQL "INSERT INTO %s (steamid, ctbantime) VALUES ('%s', %d) ON DUPLICATE KEY UPDATE ctbantime=%d"
307#define CTBAN_QUERY_TIME_UPDATE "UPDATE %s SET ctbantime = %d WHERE steamid = '%s'"
308#define CTBAN_QUERY_TIME_DELETE "DELETE FROM %s WHERE steamid = '%s'"
309
310#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))"
311#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')"
312//INSERT INTO CTBan_Log (timestamp, perp_steamid, perp_name, admin_steamid, admin_name, bantime, timeleft, reason) VALUES (123, 'asd', '%asd', '%asd', '%asd', 123, 123, CONVERT("asd" USING utf8))
313#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"
314#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"
315#define CTBAN_QUERY_LOG_EXPIRE "UPDATE %s SET timeleft=-1 WHERE perp_steamid = '%s' and timeleft >= 0"
316#define CTBAN_QUERY_LOG_V1_CHECK "SELECT ban_id FROM %s LIMIT 1"
317#define CTBAN_QUERY_LOG_TO_V2_DROPKEY "ALTER TABLE %s DROP PRIMARY KEY"
318#define CTBAN_QUERY_LOG_TO_V2_ADD_BANID "ALTER TABLE %s ADD ban_id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT FIRST"
319#define CTBAN_QUERY_LOG_UPDATE "UPDATE %s SET timeleft = %d WHERE perp_steamid = '%s' AND timeleft >= 0"
320#define CTBAN_QUERY_LOG_TIME_TO_PERM_MYSQL "UPDATE %s SET (bantime, timeleft) VALUES (0, 0) WHERE perp_steamid = '%s' AND timeleft > 0"
321#define CTBAN_QUERY_LOG_TIME_TO_PERM_SQLITE "UPDATE %s SET bantime = 0, timeleft = 0 WHERE perp_steamid = '%s' AND timeleft > 0"
322#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"
323#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"
324
325#define ZsotyoXarja "UPDATE %s SET timeleft = -7 WHERE perp_steamid = '%s' AND timeleft > 0 OR timeleft = 0"
326
327#pragma semicolon 1
328#pragma newdecls required
329
330char g_sChatBanner[MAX_CHAT_BANNER_LENGTH];
331EngineVersion g_EngineVersion = Engine_Unknown;
332Handle g_CT_Cookie = INVALID_HANDLE;
333Handle gH_TopMenu = INVALID_HANDLE;
334Handle gH_Cvar_SoundName = INVALID_HANDLE;
335char gS_SoundPath[PLATFORM_MAX_PATH];
336Handle gH_Cvar_JoinBanMessage = INVALID_HANDLE;
337Handle gH_Cvar_Database_Driver = INVALID_HANDLE;
338Handle gA_DNames = INVALID_HANDLE;
339Handle gA_DSteamIDs = INVALID_HANDLE;
340Handle gH_CP_DataBase = INVALID_HANDLE;
341Handle gH_BanDatabase = INVALID_HANDLE;
342Handle gH_Cvar_Table_Prefix = INVALID_HANDLE;
343int g_iCookieIndex;
344bool g_bAuthIdNativeExists = false;
345Handle gA_TimedBanLocalList = INVALID_HANDLE;
346int gA_LocalTimeRemaining[MAXPLAYERS+ONE];
347char g_sLogTableName[MAX_TABLE_LENGTH];
348char g_sTimesTableName[MAX_TABLE_LENGTH];
349Handle gH_Cvar_Force_Reason = INVALID_HANDLE;
350Handle gH_DArray_Reasons = INVALID_HANDLE;
351Handle gH_KV_BanLengths = INVALID_HANDLE;
352Handle gH_Cvar_CheckCTBans_Flags = INVALID_HANDLE;
353Handle gH_Cvar_IsBanned_Self = INVALID_HANDLE;
354Handle gH_Cvar_Respawn = INVALID_HANDLE;
355bool g_bA_Temp_CTBan_Override[MAXPLAYERS+ONE];
356bool g_bIgnoreOverrideResets;
357bool g_bRageBanArrayChanged;
358
359Handle g_hFrwd_OnForceCT = INVALID_HANDLE;
360Handle g_hFrwd_OnUnforceCT = INVALID_HANDLE;
361Handle g_hFrwd_OnCTBan_Offline = INVALID_HANDLE;
362Handle g_hFrwd_OnUnCTBan_Offline = INVALID_HANDLE;
363Handle g_hFrwd_OnCTBan = INVALID_HANDLE;
364Handle g_hFrwd_OnUnCTBan = INVALID_HANDLE;
365Handle g_hFrwd_CTBanInfo = INVALID_HANDLE;
366Handle g_hFrwd_CTBanInfoOffline = INVALID_HANDLE;
367
368enum eCTBanMenuHandler
369{
370 e_RemoveCTBan=ZERO,
371 e_CTBanList=ONE,
372 e_ForceCT=TWO
373}
374
375enum eQueryCallback
376{
377 e_QueryLogTableTwo=ZERO
378}
379
380enum eDatabaseType
381{
382 e_Unknown=ZERO,
383 e_MySQL=ONE,
384 e_SQLite=TWO
385}
386
387eDatabaseType g_eDatabaseType = e_Unknown;
388
389public Plugin myinfo =
390{
391 name = "CT Ban",
392 author = "databomb",
393 description = "Allows admins to ban players from joining the CT team.",
394 version = PLUGIN_VERSION,
395 url = "https://forums.alliedmods.net/showthread.php?t=166080"
396};
397
398public APLRes AskPluginLoad2(Handle hMyself, bool bLate, char[] sError, int iErr_Max)
399{
400 g_EngineVersion = GetEngineVersion();
401
402 SetCTBanChatBanner(g_EngineVersion, g_sChatBanner);
403
404 RegPluginLibrary("ctban");
405
406 CreateForwards();
407 CreateNatives();
408
409 return APLRes_Success;
410}
411
412public void OnPluginStart()
413{
414 CreateConVar("sm_ctban_version", PLUGIN_VERSION, "CT Ban Version", FCVAR_SPONLY|FCVAR_DONTRECORD|FCVAR_REPLICATED|FCVAR_NOTIFY);
415 gH_Cvar_SoundName = CreateConVar("sm_ctban_soundfile", "buttons/button11.wav", "The name of the sound to play when an action is denied.", FCVAR_NONE);
416 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);
417 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);
418 gH_Cvar_Database_Driver = CreateConVar("sm_ctban_database_driver", "default", "Specifies the configuration driver to use from SourceMod's database.cfg", FCVAR_NONE);
419 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);
420 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);
421 gH_Cvar_IsBanned_Self = CreateConVar("sm_ctban_isbanned_selftarget", "0", "Specifies whether to allow non-admins to use !isbanned on themselves.", FCVAR_NONE);
422 gH_Cvar_Respawn = CreateConVar("sm_ctban_respawn", "0", "Specifies whether players are respawned after being team changed.", FCVAR_NONE);
423
424 AutoExecConfig(true, "ctban");
425
426 g_CT_Cookie = RegClientCookie("Banned_From_CT", "Tells if you are restricted from joining the CT team", CookieAccess_Protected);
427
428 RegConsoleCmd("sm_isbanned", Command_IsBanned, "sm_isbanned <player> - Lets you know if a player is banned from CT team.");
429 RegConsoleCmd("sm_ctbanlist", Command_CTBanList, "sm_ctbanlist - Displays a list of active players who are CT Banned.");
430
431 RegAdminCmd(CTBAN_COMMAND, Command_CTBan, CTBAN_ADMIN_LEVEL, "sm_ctban <player> <time> <optional: reason> - Bans a player from being a CT.");
432 RegAdminCmd(REMOVECTBAN_COMMAND, Command_UnCTBan, UNCTBAN_ADMIN_LEVEL, "sm_removectban <player> - Unrestricts a player from being a CT.");
433 RegAdminCmd("sm_unctban", Command_UnCTBan, UNCTBAN_ADMIN_LEVEL, "sm_unctban <player> - Unrestricts a player from being a CT.");
434 RegAdminCmd(RAGEBAN_COMMAND, Command_RageBan, RAGEBAN_ADMIN_LEVEL, "sm_rageban <player> - Allows you to ban those who rage quit.");
435 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.");
436 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.");
437 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.");
438 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.");
439 RegAdminCmd(FORCECT_COMMAND, Command_ForceCT, FORCECT_ADMIN_LEVEL, "sm_forcect <player> - Temporarily overrides CTBan status and swaps player to CT team.");
440 RegAdminCmd(UNFORCECT_COMMAND, Command_UnForceCT, UNFORCECT_ADMIN_LEVEL, "sm_unforcect <player> - Removes any temporary overrides and removes player from CT team.");
441 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.");
442 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.");
443
444 LoadTranslations("ctban.phrases");
445 LoadTranslations("common.phrases");
446 LoadTranslations("clientprefs.phrases");
447 LoadTranslations("core.phrases");
448
449 // create arrays for the rage bans
450 gA_DNames = CreateArray(MAX_TARGET_LENGTH);
451 gA_DSteamIDs = CreateArray(22);
452 g_iCookieIndex = ZERO;
453
454 // Hook this to block joins when player is banned
455 AddCommandListener(Command_CheckJoin, "jointeam");
456 // This is the only sane way to deal with CS:GO auto-assign and plugin conflicts as in CS:GO Team Limit Bypass
457 HookEvent("player_spawn", Event_PlayerSpawn, EventHookMode_Post);
458 // This will catch anyone that gets swapped manually
459 HookEvent("player_team", Event_PlayerTeam, EventHookMode_Post);
460
461 // create local array for timed bans
462 // block 0: client index
463 gA_TimedBanLocalList = CreateArray(2);
464 char sAuthID[FIELD_AUTHID_MAXLENGTH];
465 for (int iIndex = ONE; iIndex <= MaxClients; iIndex++)
466 {
467 gA_LocalTimeRemaining[iIndex] = ZERO;
468
469 // Check if we need to remove anyone from CT team immediately
470 if (IsClientInGame(iIndex))
471 {
472 if (GetClientTeam(iIndex) == CS_TEAM_CT && GetCTBanStatus(iIndex))
473 {
474 EnforceCTBan(iIndex);
475
476 // Gather the time component, if needed
477 if (IsClientAuthorized(iIndex))
478 {
479 GetClientAuthId(iIndex, AuthId_Steam2, sAuthID, sizeof(sAuthID));
480 OnClientAuthorized(iIndex, sAuthID);
481 }
482 }
483 }
484 }
485
486 // periodic timer to handle timed bans
487 CreateTimer(DECREMENT_TIMEBAN_INTERVAL, Timer_CheckTimedCTBans, _, TIMER_REPEAT);
488
489 // Account for late loading
490 Handle hTopMenu;
491 if (LibraryExists("adminmenu") && ((hTopMenu = GetAdminTopMenu()) != INVALID_HANDLE))
492 {
493 OnAdminMenuReady(hTopMenu);
494 }
495
496 gH_DArray_Reasons = CreateArray(FIELD_REASON_MAXLENGTH);
497
498 if (g_EngineVersion == Engine_CSGO)
499 {
500 HookEvent("jointeam_failed", Event_JoinTeamFailed, EventHookMode_Pre);
501 }
502
503 AddMultiTargetFilter("@ctban", Filter_CTBanned_Players, "CT Banned Players", false);
504 AddMultiTargetFilter("@!ctban", Filter_NotCTBanned_Players, "Players without a CT Ban", false);
505 AddMultiTargetFilter("@noctbans", Filter_NeverCTBanned_Players, "Players who have never had a CT Ban", false);
506}
507
508public bool Filter_CTBanned_Players(const char[] sPattern, Handle hClients)
509{
510 for (int iIndex = ONE; iIndex <= MaxClients; iIndex++)
511 {
512 if (IsClientInGame(iIndex))
513 {
514 if (GetCTBanStatus(iIndex))
515 {
516 PushArrayCell(hClients, iIndex);
517 }
518 }
519 }
520
521 return true;
522}
523
524public bool Filter_NotCTBanned_Players(const char[] sPattern, Handle hClients)
525{
526 for (int iIndex = ONE; iIndex <= MaxClients; iIndex++)
527 {
528 if (IsClientInGame(iIndex))
529 {
530 if (!GetCTBanStatus(iIndex))
531 {
532 PushArrayCell(hClients, iIndex);
533 }
534 }
535 }
536
537 return true;
538}
539
540public bool Filter_NeverCTBanned_Players(const char[] sPattern, Handle hClients)
541{
542 for (int iIndex = ONE; iIndex <= MaxClients; iIndex++)
543 {
544 if (IsClientInGame(iIndex))
545 {
546 if (AreClientCookiesCached(iIndex))
547 {
548 char sCookie[MAX_COOKIE_STR_LENGTH];
549 GetClientCookie(iIndex, g_CT_Cookie, sCookie, sizeof(sCookie));
550
551 if (!strlen(sCookie))
552 {
553 PushArrayCell(hClients, iIndex);
554 }
555 }
556 }
557 }
558
559 return true;
560}
561
562void CreateNatives()
563{
564 CreateNative("CTBan_IsClientBanned", Native_IsClientBanned);
565 CreateNative("CTBan_GetTimeRemaining", Native_GetTimeRemaining);
566 CreateNative("CTBan_GetOverrideStatus", Native_GetOverrideStatus);
567 CreateNative("CTBan_GetBanInfo", Native_GetBanInfo);
568 CreateNative("CTBan_GetBanInfo_Offline", Native_GetBanInfo_Offline);
569
570 CreateNative("CTBan_Client", Native_CTBan_Client);
571 CreateNative("CTBan_Client_Offline", Native_CTBan_Client_Offline);
572 CreateNative("CTBan_ChangeBanLength", Native_CTBan_ChangeBanLength);
573
574 CreateNative("CTBan_UnbanClient", Native_CTBan_UnbanClient);
575 CreateNative("CTBan_UnbanClient_Offline", Native_CTBan_UnbanClient_Offline);
576
577 CreateNative("CTBan_ForceCT", Native_CTBan_ForceCT);
578 CreateNative("CTBan_UnForceCT", Native_CTBan_UnForceCT);
579}
580
581void CreateForwards()
582{
583 g_hFrwd_OnForceCT = CreateGlobalForward("CTBan_OnForceCT", ET_Ignore, Param_Cell, Param_Cell);
584 g_hFrwd_OnUnforceCT = CreateGlobalForward("CTBan_OnUnforceCT", ET_Ignore, Param_Cell, Param_Cell);
585
586 g_hFrwd_OnCTBan = CreateGlobalForward("CTBan_OnClientBan", ET_Ignore, Param_Cell, Param_Cell, Param_Cell, Param_String);
587 g_hFrwd_OnCTBan_Offline = CreateGlobalForward("CTBan_OnClientBan_Offline", ET_Ignore, Param_String, Param_Cell);
588
589 g_hFrwd_OnUnCTBan = CreateGlobalForward("CTBan_OnClientUnban", ET_Ignore, Param_Cell, Param_Cell);
590 g_hFrwd_OnUnCTBan_Offline = CreateGlobalForward("CTBan_OnClientUnban_Offline", ET_Ignore, Param_String, Param_Cell);
591
592 g_hFrwd_CTBanInfo = CreateGlobalForward("CTBan_GetBanInfoReturn", ET_Ignore, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_String, Param_String);
593 g_hFrwd_CTBanInfoOffline = CreateGlobalForward("CTBan_GetOfflineBanInfoReturn", ET_Ignore, Param_Cell, Param_String, Param_Cell, Param_Cell, Param_String, Param_String, Param_String);
594}
595
596public int Native_IsClientBanned(Handle hPlugin, int iParams)
597{
598 int iClient = GetNativeCell(NATIVE_ISBANNED_CELL_CLIENT);
599
600 if (iClient <= ZERO || iClient > MaxClients || !IsClientInGame(iClient))
601 {
602 ThrowNativeError(SP_ERROR_NATIVE, "Client (%d) is invalid!", iClient);
603 return ZERO;
604 }
605
606 return GetCTBanStatus(iClient);
607}
608
609public int Native_GetTimeRemaining(Handle hPlugin, int iParams)
610{
611 int iClient = GetNativeCell(NATIVE_GET_TIMELEFT_CELL_CLIENT);
612
613 if (iClient <= ZERO || iClient > MaxClients || !IsClientInGame(iClient))
614 {
615 ThrowNativeError(SP_ERROR_NATIVE, "Client (%d) is invalid!", iClient);
616 }
617
618 return gA_LocalTimeRemaining[iClient];
619}
620
621public int Native_GetOverrideStatus(Handle hPlugin, int iParams)
622{
623 int iClient = GetNativeCell(NATIVE_GET_OVERRIDE_CELL_CLIENT);
624
625 if (iClient <= ZERO || iClient > MaxClients || !IsClientInGame(iClient))
626 {
627 ThrowNativeError(SP_ERROR_NATIVE, "Client (%d) is invalid!", iClient);
628 return false;
629 }
630
631 return g_bA_Temp_CTBan_Override[iClient];
632}
633
634public int Native_GetBanInfo(Handle hPlugin, int iParams)
635{
636 int iClient = GetNativeCell(NATIVE_GETBANINFO_CELL_CLIENT);
637
638 if (iClient <= ZERO || iClient > MaxClients || !IsClientInGame(iClient))
639 {
640 ThrowNativeError(SP_ERROR_NATIVE, "Client (%d) is invalid!", iClient);
641 }
642
643 ProcessIsBannedTarget(iClient, CALLER_NATIVE);
644
645 return SP_ERROR_NONE;
646}
647
648public int Native_GetBanInfo_Offline(Handle hPlugin, int iParams)
649{
650 char sAuthId[FIELD_AUTHID_MAXLENGTH];
651 int iReturn = GetNativeString(NATIVE_GETBANINFO_OFF_STR_AUTHID, sAuthId, sizeof(sAuthId));
652
653 if (iReturn != SP_ERROR_NONE || strlen(sAuthId) < NATIVE_MIN_AUTHID_LENGTH)
654 {
655 ThrowNativeError(SP_ERROR_NATIVE, "Invalid Authid");
656 }
657
658 if (IsAuthIdConnected(sAuthId))
659 {
660 ThrowNativeError(SP_ERROR_NATIVE, "AuthID currently connected.");
661 }
662 else
663 {
664 ProcessIsBannedOffline(CALLER_NATIVE, sAuthId);
665 }
666
667 return SP_ERROR_NONE;
668}
669
670public int Native_CTBan_Client(Handle hPlugin, int iParams)
671{
672 int iClient = GetNativeCell(NATIVE_CTBAN_CELL_CLIENT);
673
674 if (iClient <= ZERO || iClient > MaxClients || !IsClientInGame(iClient))
675 {
676 ThrowNativeError(SP_ERROR_NATIVE, "Client (%d) is invalid!", iClient);
677 }
678
679 int iMinutes = GetNativeCell(NATIVE_CTBAN_CELL_TIME);
680
681 if (iMinutes < ZERO)
682 {
683 ThrowNativeError(SP_ERROR_NATIVE, "Invalid time specified (%d).", iMinutes);
684 }
685
686 int iAdmin = GetNativeCell(NATIVE_CTBAN_CELL_ADMIN);
687
688 if (iAdmin < ZERO || iAdmin > MaxClients || (iAdmin && !IsClientInGame(iAdmin)))
689 {
690 ThrowNativeError(SP_ERROR_NATIVE, "Admin (%d) is invalid!", iAdmin);
691 }
692
693 char sReason[FIELD_REASON_MAXLENGTH];
694 int iReturn = GetNativeString(NATIVE_CTBAN_STR_REASON, sReason, sizeof(sReason));
695
696 if (iReturn != SP_ERROR_NONE)
697 {
698 ThrowNativeError(SP_ERROR_NATIVE, "Invalid reason string");
699 }
700
701 if (!GetCTBanStatus(iClient))
702 {
703 PerformCTBan(iClient, iAdmin, iMinutes, _, sReason);
704 }
705 else
706 {
707 ThrowNativeError(SP_ERROR_NATIVE, g_sChatBanner, "Already CT Banned", iClient);
708 }
709
710 return SP_ERROR_NONE;
711}
712
713public int Native_CTBan_Client_Offline(Handle hPlugin, int iParams)
714{
715 if (!g_bAuthIdNativeExists)
716 {
717 ThrowNativeError(SP_ERROR_NATIVE, g_sChatBanner, "Feature Not Available");
718 }
719
720 char sAuthId[FIELD_AUTHID_MAXLENGTH];
721 int iReturn = GetNativeString(NATIVE_CTBAN_OFF_STR_AUTHID, sAuthId, sizeof(sAuthId));
722
723 if (iReturn != SP_ERROR_NONE || strlen(sAuthId) < NATIVE_MIN_AUTHID_LENGTH)
724 {
725 ThrowNativeError(SP_ERROR_NATIVE, "Invalid Authid");
726 }
727
728 if (IsAuthIdConnected(sAuthId))
729 {
730 ThrowNativeError(SP_ERROR_NATIVE, "AuthID currently connected.");
731 }
732 else
733 {
734 PerformOfflineCTBan(sAuthId, CALLER_NATIVE);
735 }
736
737 return SP_ERROR_NONE;
738}
739
740public int Native_CTBan_ChangeBanLength(Handle hPlugin, int iParams)
741{
742 int iClient = GetNativeCell(NATIVE_CHANGE_TIME_CELL_CLIENT);
743
744 if (iClient <= ZERO || iClient > MaxClients || !IsClientInGame(iClient))
745 {
746 ThrowNativeError(SP_ERROR_NATIVE, "Client (%d) is invalid!", iClient);
747 }
748
749 int iMinutes = GetNativeCell(NATIVE_CHANGE_TIME_CELL_TIME);
750
751 if (iMinutes < ZERO)
752 {
753 ThrowNativeError(SP_ERROR_NATIVE, "Invalid time specified (%d).", iMinutes);
754 }
755
756 int iAdmin = GetNativeCell(NATIVE_CHANGE_TIME_CELL_ADMIN);
757
758 if (iAdmin < ZERO || iAdmin > MaxClients || (iAdmin && !IsClientInGame(iAdmin)))
759 {
760 ThrowNativeError(SP_ERROR_NATIVE, "Admin (%d) is invalid!", iAdmin);
761 }
762
763 if (GetCTBanStatus(iClient))
764 {
765 // check if time is not changing
766 if (gA_LocalTimeRemaining[iClient] == iMinutes || (gA_LocalTimeRemaining[iClient] <= CTBAN_PERM_BAN_LENGTH && iMinutes == CTBAN_PERM_BAN_LENGTH))
767 {
768 ThrowNativeError(SP_ERROR_NATIVE, g_sChatBanner, "Invalid Amount");
769 }
770 else
771 {
772 PerformChangeCTBanTime(iClient, iAdmin, iMinutes);
773 }
774 }
775 else
776 {
777 ThrowNativeError(SP_ERROR_NATIVE, g_sChatBanner, "Not CT Banned", iClient);
778 }
779
780 return SP_ERROR_NONE;
781}
782
783public int Native_CTBan_UnbanClient(Handle hPlugin, int iParams)
784{
785 int iClient = GetNativeCell(NATIVE_UNBAN_CELL_CLIENT);
786
787 if (iClient <= ZERO || iClient > MaxClients || !IsClientInGame(iClient))
788 {
789 ThrowNativeError(SP_ERROR_NATIVE, "Client (%d) is invalid!", iClient);
790 }
791
792 int iAdmin = GetNativeCell(NATIVE_UNBAN_CELL_ADMIN);
793
794 if (iAdmin < ZERO || iAdmin > MaxClients || (iAdmin && !IsClientInGame(iAdmin)))
795 {
796 ThrowNativeError(SP_ERROR_NATIVE, "Admin (%d) is invalid!", iAdmin);
797 }
798
799 if (GetCTBanStatus(iClient))
800 {
801 // check if the cookies are ready
802 if (AreClientCookiesCached(iClient))
803 {
804 int banSolve = 0;
805 Remove_CTBan(iAdmin, iClient,false,banSolve);
806 }
807 else
808 {
809 ThrowNativeError(SP_ERROR_NATIVE, g_sChatBanner, "Cookie Status Unavailable");
810 }
811 }
812 else
813 {
814 ThrowNativeError(SP_ERROR_NATIVE, g_sChatBanner, "Not CT Banned", iClient);
815 }
816
817 return SP_ERROR_NONE;
818}
819
820public int Native_CTBan_UnbanClient_Offline(Handle hPlugin, int iParams)
821{
822 if (!g_bAuthIdNativeExists)
823 {
824 ThrowNativeError(SP_ERROR_NATIVE, g_sChatBanner, "Feature Not Available");
825 }
826
827 char sAuthId[FIELD_AUTHID_MAXLENGTH];
828 int iReturn = GetNativeString(NATIVE_UNBAN_OFF_STR_AUTHID, sAuthId, sizeof(sAuthId));
829
830 if (iReturn != SP_ERROR_NONE || strlen(sAuthId) < NATIVE_MIN_AUTHID_LENGTH)
831 {
832 ThrowNativeError(SP_ERROR_NATIVE, "Invalid Authid");
833 }
834
835 if (IsAuthIdConnected(sAuthId))
836 {
837 ThrowNativeError(SP_ERROR_NATIVE, "AuthID currently connected.");
838 }
839 else
840 {
841 PerformOfflineUnCTBan(sAuthId, CALLER_NATIVE);
842 }
843
844 return SP_ERROR_NONE;
845}
846
847public int Native_CTBan_ForceCT(Handle hPlugin, int iParams)
848{
849 int iClient = GetNativeCell(NATIVE_FORCECT_CELL_CLIENT);
850
851 if (iClient <= ZERO || iClient > MaxClients || !IsClientInGame(iClient))
852 {
853 ThrowNativeError(SP_ERROR_NATIVE, "Client (%d) is invalid!", iClient);
854 }
855
856 int iAdmin = GetNativeCell(NATIVE_FORCECT_CELL_ADMIN);
857
858 if (iAdmin < ZERO || iAdmin > MaxClients || (iAdmin && !IsClientInGame(iAdmin)))
859 {
860 ThrowNativeError(SP_ERROR_NATIVE, "Admin (%d) is invalid!", iAdmin);
861 }
862
863 if (GetClientTeam(iClient) == CS_TEAM_CT)
864 {
865 ThrowNativeError(SP_ERROR_NATIVE, g_sChatBanner, "Unable to target");
866 }
867 else
868 {
869 ForceCTActions(iAdmin, iClient);
870 }
871
872 return SP_ERROR_NONE;
873}
874
875public int Native_CTBan_UnForceCT(Handle hPlugin, int iParams)
876{
877 int iClient = GetNativeCell(NATIVE_UNFORCECT_CELL_CLIENT);
878
879 if (iClient <= ZERO || iClient > MaxClients || !IsClientInGame(iClient))
880 {
881 ThrowNativeError(SP_ERROR_NATIVE, "Client (%d) is invalid!", iClient);
882 }
883
884 int iAdmin = GetNativeCell(NATIVE_UNFORCECT_CELL_ADMIN);
885
886 if (iAdmin < ZERO || iAdmin > MaxClients || (iAdmin && !IsClientInGame(iAdmin)))
887 {
888 ThrowNativeError(SP_ERROR_NATIVE, "Admin (%d) is invalid!", iAdmin);
889 }
890
891 UnForceCTActions(iAdmin, iClient, true);
892
893 return SP_ERROR_NONE;
894}
895
896public void OnAllPluginsLoaded()
897{
898 g_bAuthIdNativeExists = IsSetAuthIdNativePresent();
899}
900
901public Action Event_PlayerSpawn(Event hEvent, const char[] sName, bool bDontBroadcast)
902{
903 int iClient = GetClientOfUserId(GetEventInt(hEvent, "userid"));
904
905 if (IsClientInGame(iClient) && GetClientTeam(iClient) == CS_TEAM_CT)
906 {
907 if (!g_bA_Temp_CTBan_Override[iClient] && GetCTBanStatus(iClient))
908 {
909 #if defined CTBAN_DEBUG
910 LogMessage("%N spawned as CT but was CTBanned. Moving to Terrorist team.", iClient);
911 #endif
912
913 EnforceCTBan(iClient);
914 }
915 }
916
917 return Plugin_Continue;
918}
919
920public Action Event_PlayerTeam(Event hEvent, const char[] sName, bool bDontBroadcast)
921{
922 int iUserID = GetEventInt(hEvent, "userid");
923 int iClient = GetClientOfUserId(iUserID);
924 int iTeam = GetEventInt(hEvent, "team");
925 bool bDisconnected = GetEventBool(hEvent, "disconnect");
926
927 if (bDisconnected || !iClient || !IsClientInGame(iClient))
928 {
929 return Plugin_Continue;
930 }
931
932 if (iTeam == CS_TEAM_CT && GetCTBanStatus(iClient))
933 {
934 // if a CT banned player is on CT and did not get an override they will be swapped after they spawn
935 // BUT an admin likely did this and should get instruction to use !forcect
936 if (!g_bA_Temp_CTBan_Override[iClient])
937 {
938 // only admins need the message
939 for (int iIndex = ONE; iIndex <= MaxClients; iIndex++)
940 {
941 if (IsClientInGame(iIndex) && CheckCommandAccess(iIndex, "sm_chat", ADMFLAG_CHAT))
942 {
943 PrintToChat(iIndex, g_sChatBanner, "CTBanned Player On CT Team", iClient);
944 }
945 }
946 }
947
948 // if they are still alive then we should not even wait until the respawn
949 if (IsPlayerAlive(iClient))
950 {
951 CreateTimer(DELAY_ENFORCEMENT_TIME, Timer_DelayEnforcement, iUserID, TIMER_FLAG_NO_MAPCHANGE);
952 }
953 }
954
955 return Plugin_Continue;
956}
957
958public Action Timer_DelayEnforcement(Handle hTimer, any iUserID)
959{
960 int iClient = GetClientOfUserId(iUserID);
961
962 if (iClient && IsClientInGame(iClient) && GetClientTeam(iClient) == CS_TEAM_CT && GetCTBanStatus(iClient))
963 {
964 EnforceCTBan(iClient);
965 }
966}
967
968public Action Event_JoinTeamFailed(Handle hEvent, const char[] sName, bool bDontBroadcast)
969{
970 int iClient = GetClientOfUserId(GetEventInt(hEvent, "userid"));
971 if (iClient && IsClientInGame(iClient))
972 {
973 int iReason = GetEventInt(hEvent, "reason");
974
975 if (iReason == JOINFAILREASON_ONECHANGE)
976 {
977 // Check if client is banned and is blocked
978 if (GetCTBanStatus(iClient))
979 {
980 #if defined CTBAN_DEBUG
981 LogMessage("%N was unable to join a team due to limit. Forcing to Terrorist team.");
982 #endif
983
984 ChangeClientTeam(iClient, CS_TEAM_T);
985
986 return Plugin_Handled;
987 }
988 }
989 }
990
991 return Plugin_Continue;
992}
993
994// consider if someone does a 'retry' and clientprefs is accessinsg on its ClientConnectCallback and this is also trying to set a value
995public void OnClientAuthorized(int iClient, const char[] sAuthID)
996{
997 // check if the Steam ID is in the Rage Ban list
998 int iNeedle = FindStringInArray(gA_DSteamIDs, sAuthID);
999 if (iNeedle != VALUE_NOT_FOUND_IN_ARRAY)
1000 {
1001 g_bRageBanArrayChanged = true;
1002
1003 RemoveFromArray(gA_DNames, iNeedle);
1004 RemoveFromArray(gA_DSteamIDs, iNeedle);
1005 #if defined CTBAN_DEBUG
1006 LogMessage("removed %N from Rage Bannable player list for re-connecting to the server", iClient);
1007 #endif
1008 }
1009
1010 // check if we have a database connection
1011 if (gH_BanDatabase != INVALID_HANDLE)
1012 {
1013 // check if the Steam ID is in the Timed Ban list
1014 char sQuery[QUERY_MAXLENGTH];
1015 Format(sQuery, sizeof(sQuery), CTBAN_QUERY_TIME_SELECT_BANTIME, g_sTimesTableName, sAuthID);
1016 SQL_TQuery(gH_BanDatabase, DB_Callback_OnClientAuthed, sQuery, view_as<int>(iClient));
1017 }
1018 else
1019 {
1020 CreateTimer(AUTH_RESCAN_TIME, Timer_OnAuthCheckDatabase, iClient, TIMER_FLAG_NO_MAPCHANGE);
1021 }
1022}
1023
1024public Action Timer_OnAuthCheckDatabase(Handle hTimer, any iClient)
1025{
1026 if (gH_BanDatabase != INVALID_HANDLE && IsClientInGame(iClient))
1027 {
1028 char sAuthID[FIELD_AUTHID_MAXLENGTH];
1029 GetClientAuthId(iClient, AuthId_Steam2, sAuthID, sizeof(sAuthID));
1030
1031 char sQuery[QUERY_MAXLENGTH];
1032 Format(sQuery, sizeof(sQuery), CTBAN_QUERY_TIME_SELECT_BANTIME, g_sTimesTableName, sAuthID);
1033 SQL_TQuery(gH_BanDatabase, DB_Callback_OnClientAuthed, sQuery, view_as<int>(iClient));
1034 SQL_SetCharset(gH_BanDatabase,"utf8");
1035 }
1036 else if(IsClientInGame(iClient))
1037 {
1038 CreateTimer(AUTH_RESCAN_TIME, Timer_OnAuthCheckDatabase, iClient, TIMER_FLAG_NO_MAPCHANGE);
1039 }
1040}
1041
1042public void DB_Callback_OnClientAuthed(Handle hOwner, Handle hCallback, const char[] sError, any iClient)
1043{
1044 if (hCallback == INVALID_HANDLE)
1045 {
1046 LogError("Error in OnClientAuthorized query: %s", sError);
1047 }
1048 else
1049 {
1050 int iRowCount = SQL_GetRowCount(hCallback);
1051 #if defined CTBAN_DEBUG
1052 LogMessage("SQL Auth: %d row count", iRowCount);
1053 #endif
1054 if (iRowCount)
1055 {
1056 SQL_FetchRow(hCallback);
1057 int iBanTimeRemaining = SQL_FetchInt(hCallback, CLIENT_AUTHED_CB_FIELD_TIMELEFT);
1058 #if defined CTBAN_DEBUG
1059 LogMessage("SQL Auth: %N joined with %i time remaining on ban", iClient, iBanTimeRemaining);
1060 #endif
1061 // update local time
1062 PushArrayCell(gA_TimedBanLocalList, iClient);
1063 gA_LocalTimeRemaining[iClient] = iBanTimeRemaining;
1064 }
1065 }
1066}
1067
1068public void AdminMenu_RageBan(Handle hTopMenu, TopMenuAction eAction, TopMenuObject eObjectID, int iClient, char[] sBuffer, int iMaxLength)
1069{
1070 if (eAction == TopMenuAction_DisplayOption)
1071 {
1072 Format(sBuffer, iMaxLength, "%T", "Rage Ban Admin Menu", iClient);
1073 }
1074 else if (eAction == TopMenuAction_SelectOption)
1075 {
1076 DisplayRageBanMenu(iClient, GetArraySize(gA_DNames));
1077 }
1078}
1079
1080void DisplayRageBanMenu(int iClient, int iArraySize)
1081{
1082 if (iArraySize == ZERO)
1083 {
1084 PrintToChat(iClient, g_sChatBanner, "No Targets");
1085 }
1086 else
1087 {
1088 Handle hMenu = CreateMenu(MenuHandler_RageBan);
1089
1090 SetMenuTitle(hMenu, "%T", "Rage Ban Menu Title", iClient);
1091 SetMenuExitBackButton(hMenu, true);
1092
1093 for (int iArrayIndex = ZERO; iArrayIndex < iArraySize; iArrayIndex++)
1094 {
1095 char sName[FIELD_NAME_MAXLENGTH];
1096 GetArrayString(gA_DNames, iArrayIndex, sName, sizeof(sName));
1097
1098 char sAuthID[FIELD_AUTHID_MAXLENGTH];
1099 GetArrayString(gA_DSteamIDs, iArrayIndex, sAuthID, sizeof(sAuthID));
1100
1101 AddMenuItem(hMenu, sAuthID, sName);
1102 }
1103
1104 DisplayMenu(hMenu, iClient, MENU_TIME_FOREVER);
1105 }
1106}
1107
1108public int MenuHandler_RageBan(Handle hMenu, MenuAction action, int iClient, int iMenuChoice)
1109{
1110 if (action == MenuAction_End)
1111 {
1112 CloseHandle(hMenu);
1113 }
1114 else if (action == MenuAction_Cancel)
1115 {
1116 if ((iMenuChoice == MenuCancel_ExitBack) && (gH_TopMenu != INVALID_HANDLE))
1117 {
1118 DisplayTopMenu(gH_TopMenu, iClient, TopMenuPosition_LastCategory);
1119 }
1120 }
1121 else if (action == MenuAction_Select)
1122 {
1123 if (!g_bAuthIdNativeExists)
1124 {
1125 ReplyToCommand(iClient, g_sChatBanner, "Feature Not Available");
1126 }
1127 else
1128 {
1129 char sAuthID[FIELD_AUTHID_MAXLENGTH];
1130 char sTargetName[MAX_TARGET_LENGTH];
1131 GetMenuItem(hMenu, iMenuChoice, sAuthID, sizeof(sAuthID), _, sTargetName, sizeof(sTargetName));
1132
1133 #if defined CTBAN_DEBUG
1134 PrintToChat(iClient, g_sChatBanner, "Ready to CT Ban", sAuthID);
1135 #endif
1136
1137 SetAuthIdCookie(sAuthID, g_CT_Cookie, COOKIE_BANNED_STRING);
1138
1139 char sAdminSteamID[FIELD_AUTHID_MAXLENGTH];
1140 GetClientAuthId(iClient, AuthId_Steam2, sAdminSteamID, sizeof(sAdminSteamID));
1141
1142 LogMessage("%N (%s) has issued a rage ban on %s (%s) indefinitely.", iClient, sAdminSteamID, sTargetName, sAuthID);
1143
1144 ShowActivity2(iClient, "", g_sChatBanner, "Rage Ban", sTargetName);
1145
1146 int iTimeStamp = GetTime();
1147 char sTempName[FIELD_NAME_MAXLENGTH];
1148 char sQuery[QUERY_MAXLENGTH];
1149 char sEscapedPerpName[MAX_SAFE_ESCAPE_QUERY(FIELD_NAME_MAXLENGTH)];
1150 char sEscapedAdminName[MAX_SAFE_ESCAPE_QUERY(FIELD_NAME_MAXLENGTH)];
1151 Format(sTempName, sizeof(sTempName), "%s", sTargetName);
1152 SQL_EscapeString(gH_BanDatabase, sTempName, sEscapedPerpName, sizeof(sEscapedPerpName));
1153 Format(sTempName, sizeof(sTempName), "%N", iClient);
1154 SQL_EscapeString(gH_BanDatabase, sTempName, sEscapedAdminName, sizeof(sEscapedAdminName));
1155
1156 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);
1157
1158 #if defined CTBAN_DEBUG
1159 LogMessage("log query: %s", sQuery);
1160 #endif
1161
1162 SQL_TQuery(gH_BanDatabase, DB_Callback_CTBan, sQuery, iClient);
1163
1164 // Remove any existing time information to make the CTBan permanently
1165 Format(sQuery, sizeof(sQuery), CTBAN_QUERY_TIME_DELETE, g_sTimesTableName, sAuthID);
1166 SQL_TQuery(gH_BanDatabase, DB_Callback_DisconnectAction, sQuery);
1167 }
1168 }
1169}
1170
1171public void CP_Callback_ResetAllCTBans(Handle hOwner, Handle hCallback, const char[] sError, any data)
1172{
1173 if (hCallback == INVALID_HANDLE)
1174 {
1175 LogError("Error reseting the CTBan cookies: %s", sError);
1176 }
1177 else
1178 {
1179 LogMessage("CTBans Cookie Bans were successfully RESET by the administrator.");
1180 }
1181}
1182
1183public Action Command_Offline_CTBan(int iClient, int iArgs)
1184{
1185 if (g_bAuthIdNativeExists)
1186 {
1187 char sAuthId[FIELD_AUTHID_MAXLENGTH];
1188 GetCmdArgString(sAuthId, sizeof(sAuthId));
1189
1190 if (IsAuthIdConnected(sAuthId))
1191 {
1192 ReplyToCommand(iClient, g_sChatBanner, "Unable to target");
1193 }
1194 else
1195 {
1196 PerformOfflineCTBan(sAuthId, iClient);
1197 }
1198 }
1199 else
1200 {
1201 ReplyToCommand(iClient, g_sChatBanner, "Feature Not Available");
1202 }
1203 return Plugin_Handled;
1204}
1205
1206void PerformOfflineCTBan(char[] sAuthId, int iAdmin)
1207{
1208 SetAuthIdCookie(sAuthId, g_CT_Cookie, COOKIE_BANNED_STRING);
1209
1210 char sAdminSteamID[FIELD_AUTHID_MAXLENGTH];
1211 if (iAdmin > ZERO)
1212 {
1213 GetClientAuthId(iAdmin, AuthId_Steam2, sAdminSteamID, sizeof(sAdminSteamID));
1214 }
1215 else
1216 {
1217 sAdminSteamID = CONSOLE_AUTHID;
1218 }
1219
1220 int iTimeStamp = GetTime();
1221 char sQuery[QUERY_MAXLENGTH];
1222 char sTempName[FIELD_NAME_MAXLENGTH];
1223 char sEscapedPerpAuthId[MAX_SAFE_ESCAPE_QUERY(FIELD_NAME_MAXLENGTH)];
1224 SQL_EscapeString(gH_BanDatabase, sAuthId, sEscapedPerpAuthId, sizeof(sEscapedPerpAuthId));
1225
1226 char sEscapedAdminName[MAX_SAFE_ESCAPE_QUERY(FIELD_NAME_MAXLENGTH)];
1227 if (iAdmin > ZERO)
1228 {
1229 Format(sTempName, sizeof(sTempName), "%N", iAdmin);
1230 SQL_EscapeString(gH_BanDatabase, sTempName, sEscapedAdminName, sizeof(sEscapedAdminName));
1231 }
1232 else
1233 {
1234 sEscapedAdminName = CONSOLE_USER_NAME;
1235 }
1236
1237 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);
1238
1239 #if defined CTBAN_DEBUG
1240 LogMessage("log query: %s", sQuery);
1241 #endif
1242
1243 SQL_TQuery(gH_BanDatabase, DB_Callback_CTBan, sQuery, iAdmin);
1244
1245 if (iAdmin == CALLER_NATIVE)
1246 {
1247 // No response
1248 }
1249 {
1250 ReplyToCommand(iAdmin, g_sChatBanner, "Banned AuthId", sAuthId);
1251 }
1252
1253 Call_StartForward(g_hFrwd_OnCTBan_Offline);
1254 Call_PushString(sAuthId);
1255 Call_PushCell(iAdmin);
1256 Call_Finish();
1257}
1258
1259public Action Command_ForceCT(int iClient, int iArgs)
1260{
1261 if (!iClient && !iArgs)
1262 {
1263 ReplyToCommand(iClient, g_sChatBanner, "Command Usage", "sm_forcect <player>");
1264 return Plugin_Handled;
1265 }
1266
1267 if (!iArgs)
1268 {
1269 DisplayCTBannedPlayerMenu(iClient, e_ForceCT);
1270 return Plugin_Handled;
1271 }
1272
1273 char sTarget[MAX_TARGET_LENGTH];
1274 GetCmdArg(FORCECT_ARG_TARGET, sTarget, sizeof(sTarget));
1275
1276 char sClientName[MAX_TARGET_LENGTH];
1277 int aiTargetList[MAXPLAYERS];
1278 int iTargetCount;
1279 bool b_tn_is_ml;
1280 iTargetCount = ProcessTargetString(sTarget, iClient, aiTargetList, MAXPLAYERS, COMMAND_FILTER_NO_MULTI, sClientName, sizeof(sClientName), b_tn_is_ml);
1281
1282 if (iTargetCount < ONE)
1283 {
1284 ReplyToTargetError(iClient, iTargetCount);
1285 }
1286 else
1287 {
1288 int iTarget = aiTargetList[ZERO];
1289
1290 if (iTarget && IsClientInGame(iTarget))
1291 {
1292 if (GetClientTeam(iTarget) == CS_TEAM_CT)
1293 {
1294 ReplyToCommand(iClient, g_sChatBanner, "Unable to target");
1295 }
1296 else
1297 {
1298 ForceCTActions(iClient, iTarget);
1299 }
1300 }
1301 }
1302 return Plugin_Handled;
1303}
1304
1305void ForceCTActions(int iAdmin, int iTarget)
1306{
1307 if (IsClientInGame(iTarget))
1308 {
1309 g_bA_Temp_CTBan_Override[iTarget] = true;
1310
1311 if (IsPlayerAlive(iTarget))
1312 {
1313 StripAllWeapons(iTarget);
1314 ForcePlayerSuicide(iTarget);
1315 }
1316
1317 ChangeClientTeam(iTarget, CS_TEAM_CT);
1318
1319 if (GetConVarBool(gH_Cvar_Respawn))
1320 {
1321 CS_RespawnPlayer(iTarget);
1322 }
1323
1324 ShowActivity2(iAdmin, "", g_sChatBanner, "Force CT", iTarget);
1325
1326 Call_StartForward(g_hFrwd_OnForceCT);
1327 Call_PushCell(iTarget);
1328 Call_PushCell(iAdmin);
1329 Call_Finish();
1330 }
1331}
1332
1333public Action Command_UnForceCT(int iClient, int iArgs)
1334{
1335 if (!iClient && !iArgs)
1336 {
1337 ReplyToCommand(iClient, g_sChatBanner, "Command Usage", "sm_unforcect <player>");
1338 return Plugin_Handled;
1339 }
1340
1341 if (!iArgs)
1342 {
1343 DisplayUnForceCTPlayerMenu(iClient);
1344 return Plugin_Handled;
1345 }
1346
1347 char sTarget[MAX_TARGET_LENGTH];
1348 GetCmdArg(UNFORCECT_ARG_TARGET, sTarget, sizeof(sTarget));
1349
1350 char sClientName[MAX_TARGET_LENGTH];
1351 int aiTargetLlist[MAXPLAYERS];
1352 int iTargetCount;
1353 bool b_tn_is_ml;
1354 iTargetCount = ProcessTargetString(sTarget, iClient, aiTargetLlist, MAXPLAYERS, COMMAND_FILTER_NO_MULTI, sClientName, sizeof(sClientName), b_tn_is_ml);
1355
1356 if (iTargetCount < ONE)
1357 {
1358 ReplyToTargetError(iClient, iTargetCount);
1359 }
1360 else
1361 {
1362 int iTarget = aiTargetLlist[ZERO];
1363 UnForceCTActions(iClient, iTarget);
1364 }
1365 return Plugin_Handled;
1366}
1367
1368void UnForceCTActions(int iAdmin, int iTarget, bool bQuiet = false)
1369{
1370 if (!g_bA_Temp_CTBan_Override[iTarget])
1371 {
1372 if (!bQuiet)
1373 {
1374 ReplyToCommand(iAdmin, g_sChatBanner, "Unable to target");
1375 }
1376 }
1377 else
1378 {
1379 if (IsClientInGame(iTarget))
1380 {
1381 if (GetClientTeam(iTarget) == CS_TEAM_CT)
1382 {
1383 if (IsPlayerAlive(iTarget))
1384 {
1385 StripAllWeapons(iTarget);
1386 ForcePlayerSuicide(iTarget);
1387 }
1388
1389 ChangeClientTeam(iTarget, CS_TEAM_T);
1390
1391 if (GetConVarBool(gH_Cvar_Respawn))
1392 {
1393 CS_RespawnPlayer(iTarget);
1394 }
1395 }
1396 g_bA_Temp_CTBan_Override[iTarget] = false;
1397
1398 if (!bQuiet)
1399 {
1400 ShowActivity2(iAdmin, "", g_sChatBanner, "Unforce CT", iTarget);
1401 }
1402
1403 Call_StartForward(g_hFrwd_OnUnforceCT);
1404 Call_PushCell(iTarget);
1405 Call_PushCell(iAdmin);
1406 Call_Finish();
1407 }
1408 }
1409}
1410
1411void DisplayUnForceCTPlayerMenu(int iClient)
1412{
1413 Handle hMenu = CreateMenu(MenuHandler_UnForceCT);
1414
1415 SetMenuTitle(hMenu, "%T", "UnForce CT Menu Title", iClient);
1416 SetMenuExitBackButton(hMenu, true);
1417
1418 int iCount = ZERO;
1419 char sUserId[MAX_USERID_LENGTH];
1420 char sName[MAX_NAME_LENGTH];
1421
1422 // filter away those with current overrides
1423 for (int iIndex = ONE; iIndex <= MaxClients; iIndex++)
1424 {
1425 if (IsClientInGame(iIndex))
1426 {
1427 if (g_bA_Temp_CTBan_Override[iIndex])
1428 {
1429 IntToString(GetClientUserId(iIndex), sUserId, sizeof(sUserId));
1430 GetClientName(iIndex, sName, sizeof(sName));
1431
1432 AddMenuItem(hMenu, sUserId, sName);
1433
1434 iCount++;
1435 }
1436 }
1437 }
1438
1439 if (!iCount)
1440 {
1441 PrintToChat(iClient, g_sChatBanner, "No matching clients");
1442 }
1443
1444 DisplayMenu(hMenu, iClient, MENU_TIME_FOREVER);
1445}
1446
1447public Action Command_ResetCookies(int iClient, int iArgs)
1448{
1449 char sArgs[MAX_RESET_ARG_LENGTH];
1450 GetCmdArgString(sArgs, sizeof(sArgs));
1451
1452 if (StrEqual("force", sArgs))
1453 {
1454 if (!g_iCookieIndex)
1455 {
1456 ReplyToCommand(iClient, g_sChatBanner, "Cookie not Found", "Banned_From_CT");
1457 }
1458 else
1459 {
1460 char sQuery[QUERY_MAXLENGTH];
1461 Format(sQuery, sizeof(sQuery), CTBAN_QUERY_CP_RESET_COOKIES, g_iCookieIndex);
1462
1463 #if defined CTBAN_DEBUG
1464 LogMessage("Query to run: %s", sQuery);
1465 #endif
1466
1467 SQL_TQuery(gH_CP_DataBase, CP_Callback_ResetAllCTBans, sQuery);
1468 //SQL_SetCharset(gH_CP_DataBase,"utf8"); //mocskosgecikurvaanyádatteszar
1469 ShowActivity2(iClient, "", g_sChatBanner, "Reset Cookies");
1470 }
1471 }
1472 else
1473 {
1474 ReplyToCommand(iClient, g_sChatBanner, "Reset Cookie Confirmation");
1475 }
1476
1477 return Plugin_Handled;
1478}
1479
1480public Action Command_Offline_UnCTBan(int iClient, int iArgs)
1481{
1482 if (g_bAuthIdNativeExists)
1483 {
1484 char sAuthId[FIELD_AUTHID_MAXLENGTH];
1485 GetCmdArgString(sAuthId, sizeof(sAuthId));
1486
1487 if (IsAuthIdConnected(sAuthId))
1488 {
1489 ReplyToCommand(iClient, g_sChatBanner, "Unable to target");
1490 }
1491 else
1492 {
1493 PerformOfflineUnCTBan(sAuthId, iClient);
1494 }
1495 }
1496 else
1497 {
1498 ReplyToCommand(iClient, g_sChatBanner, "Feature Not Available");
1499 }
1500
1501 return Plugin_Handled;
1502}
1503
1504void PerformOfflineUnCTBan(char[] sAuthId, int iAdmin)
1505{
1506 SetAuthIdCookie(sAuthId, g_CT_Cookie, COOKIE_UNBANNED_STRING);
1507
1508 char sEscapedAuthId[MAX_SAFE_ESCAPE_QUERY(FIELD_NAME_MAXLENGTH)];
1509 SQL_EscapeString(gH_BanDatabase, sAuthId, sEscapedAuthId, sizeof(sEscapedAuthId));
1510
1511 char sQuery[QUERY_MAXLENGTH];
1512 Format(sQuery, sizeof(sQuery), CTBAN_QUERY_LOG_EXPIRE, g_sLogTableName, sEscapedAuthId);
1513
1514 #if defined CTBAN_DEBUG
1515 LogMessage("log query: %s", sQuery);
1516 #endif
1517
1518 SQL_TQuery(gH_BanDatabase, DB_Callback_RemoveCTBan, sQuery, CALLER_DO_NOT_REPLY);
1519
1520 // delete from the timedban database if there was one
1521 Format(sQuery, sizeof(sQuery), CTBAN_QUERY_TIME_DELETE, g_sTimesTableName, sEscapedAuthId);
1522
1523 #if defined CTBAN_DEBUG
1524 LogMessage("log query: %s", sQuery);
1525 #endif
1526
1527 SQL_TQuery(gH_BanDatabase, DB_Callback_RemoveCTBan, sQuery, CALLER_DO_NOT_REPLY);
1528
1529 if (iAdmin == CALLER_NATIVE)
1530 {
1531 // No response
1532 }
1533 else
1534 {
1535 ReplyToCommand(iAdmin, g_sChatBanner, "Unbanned AuthId", sAuthId);
1536
1537 LogMessage("%N has removed the CT ban on %s.", iAdmin, sAuthId);
1538 }
1539
1540 Call_StartForward(g_hFrwd_OnUnCTBan_Offline);
1541 Call_PushString(sAuthId);
1542 Call_PushCell(iAdmin);
1543 Call_Finish();
1544}
1545
1546public Action Command_RageBan(int iClient, int iArgs)
1547{
1548 int iArraySize = GetArraySize(gA_DNames);
1549 if (iArraySize == ZERO)
1550 {
1551 ReplyToCommand(iClient, g_sChatBanner, "No Targets");
1552 return Plugin_Handled;
1553 }
1554
1555 if (!iArgs)
1556 {
1557 if (iClient)
1558 {
1559 DisplayRageBanMenu(iClient, iArraySize);
1560 }
1561 // Console user
1562 else
1563 {
1564 PrintToServer(g_sChatBanner, "Rage Ban Menu Title");
1565
1566 for (int iArrayIndex = ZERO; iArrayIndex < iArraySize; iArrayIndex++)
1567 {
1568 char sName[FIELD_NAME_MAXLENGTH];
1569 GetArrayString(gA_DNames, iArrayIndex, sName, sizeof(sName));
1570
1571 char sAuthID[FIELD_AUTHID_MAXLENGTH];
1572 GetArrayString(gA_DSteamIDs, iArrayIndex, sAuthID, sizeof(sAuthID));
1573
1574 PrintToServer("[CTBAN] (%d.) %s [%s]", iArrayIndex + ONE, sName, sAuthID);
1575 }
1576
1577 g_bRageBanArrayChanged = false;
1578 }
1579 return Plugin_Handled;
1580 }
1581 else
1582 {
1583 if (iClient)
1584 {
1585 ReplyToCommand(iClient, g_sChatBanner, "Command Usage", RAGEBAN_COMMAND);
1586 }
1587 // Console user
1588 else
1589 {
1590 char sTarget[MAX_MENU_INT_CHOICE_LENGTH];
1591 GetCmdArg(RAGEBAN_ARG_CONSOLE_TARGET, sTarget, sizeof(sTarget));
1592
1593 int iArrayIndex = StringToInt(sTarget) - ONE;
1594
1595 if ((iArrayIndex >= iArraySize) || (iArrayIndex < ZERO))
1596 {
1597 ReplyToCommand(iClient, g_sChatBanner, "No matching client");
1598 }
1599 else if (g_bRageBanArrayChanged)
1600 {
1601 ReplyToCommand(iClient, g_sChatBanner, "Player no longer available");
1602 }
1603 else
1604 {
1605 char sTargetName[FIELD_NAME_MAXLENGTH];
1606 GetArrayString(gA_DNames, iArrayIndex, sTargetName, sizeof(sTargetName));
1607
1608 char sAuthID[FIELD_AUTHID_MAXLENGTH];
1609 GetArrayString(gA_DSteamIDs, iArrayIndex, sAuthID, sizeof(sAuthID));
1610
1611 #if defined CTBAN_DEBUG
1612 PrintToServer(g_sChatBanner, "Ready to CT Ban", sAuthID);
1613 #endif
1614
1615 SetAuthIdCookie(sAuthID, g_CT_Cookie, COOKIE_BANNED_STRING);
1616
1617 LogMessage("%N has issued a rage ban on %s (%s) indefinitely.", iClient, sTargetName, sAuthID);
1618
1619 ShowActivity2(iClient, "", g_sChatBanner, "Rage Ban", sTargetName);
1620
1621 int iTimeStamp = GetTime();
1622 char sTempName[FIELD_NAME_MAXLENGTH];
1623 char sQuery[QUERY_MAXLENGTH];
1624 char sEscapedPerpName[MAX_SAFE_ESCAPE_QUERY(FIELD_NAME_MAXLENGTH)];
1625 Format(sTempName, sizeof(sTempName), "%s", sTargetName);
1626 SQL_EscapeString(gH_BanDatabase, sTempName, sEscapedPerpName, sizeof(sEscapedPerpName));
1627
1628 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);
1629
1630 #if defined CTBAN_DEBUG
1631 LogMessage("log query: %s", sQuery);
1632 #endif
1633
1634 SQL_TQuery(gH_BanDatabase, DB_Callback_CTBan, sQuery, iClient);
1635
1636 // Remove any existing time information to make the CTBan permanently
1637 Format(sQuery, sizeof(sQuery), CTBAN_QUERY_TIME_DELETE, g_sTimesTableName, sAuthID);
1638 SQL_TQuery(gH_BanDatabase, DB_Callback_DisconnectAction, sQuery);
1639 }
1640 }
1641 }
1642
1643 return Plugin_Handled;
1644}
1645
1646public Action Timer_CheckTimedCTBans(Handle hTimer)
1647{
1648 // check if anyone has a time
1649 int iTimeArraySize = GetArraySize(gA_TimedBanLocalList);
1650
1651 // credit for this idea goes to Kigen
1652 for (int iIndex = ZERO; iIndex < iTimeArraySize; iIndex++)
1653 {
1654 int iBannedClientIndex = GetArrayCell(gA_TimedBanLocalList, iIndex);
1655 if (IsClientInGame(iBannedClientIndex))
1656 {
1657 if (IsPlayerAlive(iBannedClientIndex))
1658 {
1659 gA_LocalTimeRemaining[iBannedClientIndex]--;
1660
1661 #if defined CTBAN_DEBUG
1662 LogMessage("found alive time banned client with %i remaining", gA_LocalTimeRemaining[iBannedClientIndex]);
1663 #endif
1664
1665 // check if we should remove the CT ban
1666 if (gA_LocalTimeRemaining[iBannedClientIndex] <= ZERO)
1667 {
1668 // remove CT ban
1669 RemoveFromArray(gA_TimedBanLocalList, iIndex);
1670 iTimeArraySize--;
1671 int banSolve = 0;
1672 Remove_CTBan(ZERO, iBannedClientIndex, true,banSolve);
1673
1674 #if defined CTBAN_DEBUG
1675 LogMessage("removed CT ban on %N", iBannedClientIndex);
1676 #endif
1677 }
1678 }
1679 }
1680 }
1681}
1682
1683public void OnConfigsExecuted()
1684{
1685 #if defined CTBAN_DEBUG
1686 LogMessage("Connecting to clientprefs database");
1687 #endif
1688
1689 SQL_TConnect(CP_Callback_Connect, "clientprefs");
1690
1691 char sDatabaseDriver[64];
1692 GetConVarString(gH_Cvar_Database_Driver, sDatabaseDriver, sizeof(sDatabaseDriver));
1693
1694 #if defined CTBAN_DEBUG
1695 LogMessage("Connecting to log database");
1696 #endif
1697
1698 SQL_TConnect(DB_Callback_Connect, sDatabaseDriver);
1699
1700 ParseCTBanReasonsFile(gH_DArray_Reasons);
1701
1702 gH_KV_BanLengths = ParseCTBanLengthsFile(gH_KV_BanLengths);
1703}
1704
1705public void DB_Callback_Connect(Handle hOwner, Handle hCallback, const char[] sError, any data)
1706{
1707 if (hCallback == INVALID_HANDLE)
1708 {
1709 LogError("Default database database connection failure: %s", sError);
1710 SetFailState("Error while connecting to default database. Exiting.");
1711 }
1712 else
1713 {
1714 gH_BanDatabase = hCallback;
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 else
2717 Format(sQuery, sizeof(sQuery), CTBAN_QUERY_LOG_EXPIRE, g_sLogTableName, sTargetSteam);
2718
2719 //LogError("Fingtam: %s , %d",sQuery,banSolve);
2720
2721 #if defined CTBAN_DEBUG
2722 LogMessage("log query: %s", sQuery);
2723 #endif
2724
2725 SQL_TQuery(gH_BanDatabase, DB_Callback_RemoveCTBan, sQuery, iTarget);
2726
2727 LogMessage("%N has removed the CT ban on %N (%s).", iAdmin, iTarget, sTargetSteam);
2728
2729 if (!bExpired)
2730 {
2731 ShowActivity2(iAdmin, "", g_sChatBanner, "CT Ban Removed", iTarget);
2732 }
2733 else
2734 {
2735 ShowActivity2(iAdmin, "", g_sChatBanner, "CT Ban Auto Removed", iTarget);
2736 }
2737
2738 // delete from the timedban database if there was one
2739 Format(sQuery, sizeof(sQuery), CTBAN_QUERY_TIME_DELETE, g_sTimesTableName, sTargetSteam);
2740
2741 SQL_TQuery(gH_BanDatabase, DB_Callback_RemoveCTBan, sQuery, iTarget);
2742 }
2743 else
2744 {
2745 ReplyToCommand(iAdmin, g_sChatBanner, "Not CT Banned", iTarget);
2746 }
2747
2748 // error on side of caution and just set cookie to 0 regardless of what it was
2749 SetClientCookie(iTarget, g_CT_Cookie, COOKIE_UNBANNED_STRING);
2750
2751 g_bA_Temp_CTBan_Override[iTarget] = false;
2752
2753 Call_StartForward(g_hFrwd_OnUnCTBan);
2754 Call_PushCell(iTarget);
2755 Call_PushCell(iAdmin);
2756 Call_Finish();
2757}
2758
2759public void DB_Callback_RemoveCTBan(Handle hOwner, Handle hCallback, const char[] sError, any iClient)
2760{
2761 if (hCallback == INVALID_HANDLE)
2762 {
2763 LogError("Error handling steamID after CT ban removal: %s", sError);
2764 }
2765 else
2766 {
2767 #if defined CTBAN_DEBUG
2768 if (iClient > ZERO && IsClientInGame(iClient))
2769 {
2770 LogMessage("CTBan on %N was removed in SQL", iClient);
2771 }
2772 else
2773 {
2774 LogMessage("CTBan on --- was removed in SQL");
2775 }
2776 #endif
2777 }
2778}
2779
2780public Action Command_CTBan(int iClient, int iArgs)
2781{
2782 if (!iClient && (iArgs < (GetConVarBool(gH_Cvar_Force_Reason) ? CTBAN_ARG_REASON : CTBAN_ARG_TIME)))
2783 {
2784 if (GetConVarBool(gH_Cvar_Force_Reason))
2785 {
2786 ReplyToCommand(iClient, g_sChatBanner, "Command Usage", "sm_ctban <player> <time> <reason>");
2787 }
2788 else
2789 {
2790 ReplyToCommand(iClient, g_sChatBanner, "Command Usage", "sm_ctban <player> <time> <optional:reason>");
2791 }
2792
2793 return Plugin_Handled;
2794 }
2795
2796 if (!iArgs)
2797 {
2798 DisplayCTBanPlayerMenu(iClient);
2799 return Plugin_Handled;
2800 }
2801
2802 char sTarget[MAX_NAME_LENGTH];
2803 GetCmdArg(CTBAN_ARG_PLAYER, sTarget, sizeof(sTarget));
2804
2805 char sClientName[MAX_TARGET_LENGTH];
2806 int aiTargetList[MAXPLAYERS];
2807 int iTargetCount;
2808 bool b_tn_is_ml;
2809 iTargetCount = ProcessTargetString(sTarget, iClient, aiTargetList, MAXPLAYERS, COMMAND_FILTER_NO_MULTI, sClientName, sizeof(sClientName), b_tn_is_ml);
2810
2811 // target count 0 or less is an error condition
2812 if (iTargetCount < ONE)
2813 {
2814 ReplyToTargetError(iClient, iTargetCount);
2815 }
2816 else
2817 {
2818 int iTarget = aiTargetList[ZERO];
2819
2820 if(iTarget && IsClientInGame(iTarget))
2821 {
2822 if (GetCTBanStatus(iTarget, iClient))
2823 {
2824 ReplyToCommand(iClient, g_sChatBanner, "Already CT Banned", iTarget);
2825 }
2826 else
2827 {
2828 if (iArgs == CTBAN_ARG_PLAYER)
2829 {
2830 int iTargetUserId = GetClientUserId(iTarget);
2831 DisplayCTBanTimeMenu(iClient, iTargetUserId);
2832 return Plugin_Handled;
2833 }
2834
2835 char sBanTime[MAX_TIME_ARG_LENGTH];
2836 GetCmdArg(CTBAN_ARG_TIME, sBanTime, sizeof(sBanTime));
2837 int iBanTime = StringToInt(sBanTime);
2838
2839 if (GetConVarBool(gH_Cvar_Force_Reason) && iArgs == CTBAN_ARG_TIME)
2840 {
2841 int iTargetUserId = GetClientUserId(iTarget);
2842 DisplayCTBanReasonMenu(iClient, iTargetUserId, iBanTime);
2843 return Plugin_Handled;
2844 }
2845
2846 char sReasonStr[FIELD_REASON_MAXLENGTH];
2847 char sArgPart[FIELD_REASON_MAXLENGTH];
2848 for (int iArg = CTBAN_ARG_REASON; iArg <= iArgs; iArg++)
2849 {
2850 GetCmdArg(iArg, sArgPart, sizeof(sArgPart));
2851 Format(sReasonStr, sizeof(sReasonStr), "%s %s", sReasonStr, sArgPart);
2852 }
2853 // Remove the space at the beginning
2854 TrimString(sReasonStr);
2855
2856 if (GetConVarBool(gH_Cvar_Force_Reason) && !strlen(sReasonStr))
2857 {
2858 ReplyToCommand(iClient, g_sChatBanner, "Reason Required");
2859 }
2860 else
2861 {
2862 PerformCTBan(iTarget, iClient, iBanTime, _, sReasonStr);
2863 }
2864 }
2865 }
2866 }
2867 return Plugin_Handled;
2868}
2869
2870void PerformCTBan(int iClient, int iAdmin, int iBanTime = CTBAN_PERM_BAN_LENGTH, int iReason = CTBAN_NO_REASON_GIVEN, char[] sManualReason="")
2871{
2872 // set cookie to ban
2873 SetClientCookie(iClient, g_CT_Cookie, COOKIE_BANNED_STRING);
2874
2875 char sTargetAuthID[FIELD_AUTHID_MAXLENGTH];
2876 GetClientAuthId(iClient, AuthId_Steam2, sTargetAuthID, sizeof(sTargetAuthID));
2877
2878 // check if they're on CT team
2879 if (GetClientTeam(iClient) == CS_TEAM_CT)
2880 {
2881 EnforceCTBan(iClient);
2882 }
2883
2884 char sReason[FIELD_REASON_MAXLENGTH];
2885 if (strlen(sManualReason) > ZERO)
2886 {
2887 Format(sReason, sizeof(sReason), "%s", sManualReason);
2888 }
2889 // or else they picked a reason # from the admin menu
2890 else
2891 {
2892 // Check if we are using the translated phrase reasons or the manual file reasons
2893 int iNumManualReasons = GetArraySize(gH_DArray_Reasons);
2894
2895 // manual file reasons
2896 if (iNumManualReasons > ZERO)
2897 {
2898 if (iReason == CTBAN_NO_REASON_GIVEN)
2899 {
2900 Format(sReason, sizeof(sReason), "No reason given.");
2901 }
2902 else
2903 {
2904 GetArrayString(gH_DArray_Reasons, iReason, sReason, sizeof(sReason));
2905 }
2906 }
2907 // translated phrases reasons
2908 else
2909 {
2910 switch (iReason)
2911 {
2912 case ONE:
2913 {
2914 Format(sReason, sizeof(sReason), "%T", "CT Ban Reason 1", iAdmin);
2915 }
2916 case TWO:
2917 {
2918 Format(sReason, sizeof(sReason), "%T", "CT Ban Reason 2", iAdmin);
2919 }
2920 case THREE:
2921 {
2922 Format(sReason, sizeof(sReason), "%T", "CT Ban Reason 3", iAdmin);
2923 }
2924 case FOUR:
2925 {
2926 Format(sReason, sizeof(sReason), "%T", "CT Ban Reason 4", iAdmin);
2927 }
2928 case FIVE:
2929 {
2930 Format(sReason, sizeof(sReason), "%T", "CT Ban Reason 5", iAdmin);
2931 }
2932 case SIX:
2933 {
2934 Format(sReason, sizeof(sReason), "%T", "CT Ban Reason 6", iAdmin);
2935 }
2936 case SEVEN:
2937 {
2938 Format(sReason, sizeof(sReason), "%T", "CT Ban Reason 7", iAdmin);
2939 }
2940 default:
2941 {
2942 Format(sReason, sizeof(sReason), "No reason given.");
2943 }
2944 }
2945 }
2946 }
2947
2948 int iTimeStamp = GetTime();
2949
2950 char sTempName[FIELD_NAME_MAXLENGTH];
2951 char sQuery[QUERY_MAXLENGTH];
2952
2953 char sEscapedPerpName[MAX_SAFE_ESCAPE_QUERY(FIELD_NAME_MAXLENGTH)];
2954 Format(sTempName, sizeof(sTempName), "%N", iClient);
2955 SQL_EscapeString(gH_BanDatabase, sTempName, sEscapedPerpName, sizeof(sEscapedPerpName));
2956
2957 char sEscapedReason[MAX_SAFE_ESCAPE_QUERY(FIELD_REASON_MAXLENGTH)];
2958 SQL_EscapeString(gH_BanDatabase, sReason, sEscapedReason, sizeof(sEscapedReason));
2959
2960 if(iAdmin && IsClientInGame(iAdmin))
2961 {
2962 char sAdminAuthID[FIELD_AUTHID_MAXLENGTH];
2963 GetClientAuthId(iAdmin, AuthId_Steam2, sAdminAuthID, sizeof(sAdminAuthID));
2964
2965 char sEscapedAdminName[MAX_SAFE_ESCAPE_QUERY(FIELD_NAME_MAXLENGTH)];
2966 Format(sTempName, sizeof(sTempName), "%N", iAdmin);
2967 SQL_EscapeString(gH_BanDatabase, sTempName, sEscapedAdminName, sizeof(sEscapedAdminName));
2968
2969 Format(sQuery, sizeof(sQuery), CTBAN_QUERY_LOG_INSERT, g_sLogTableName, iTimeStamp, sTargetAuthID, sEscapedPerpName, sAdminAuthID, sEscapedAdminName, iBanTime, iBanTime, sEscapedReason);
2970
2971 #if defined CTBAN_DEBUG
2972 LogMessage("log query: %s", sQuery);
2973 #endif
2974
2975 SQL_TQuery(gH_BanDatabase, DB_Callback_CTBan, sQuery, iClient);
2976
2977 LogMessage("%N (%s) has issued a CT ban on %N (%s) for %d minutes for %s.", iAdmin, sAdminAuthID, iClient, sTargetAuthID, iBanTime, sReason);
2978 }
2979 else
2980 {
2981 Format(sQuery, sizeof(sQuery), CTBAN_QUERY_LOG_INSERT, g_sLogTableName, iTimeStamp, sTargetAuthID, sEscapedPerpName, CONSOLE_AUTHID, CONSOLE_USER_NAME, iBanTime, iBanTime, sEscapedReason);
2982
2983 #if defined CTBAN_DEBUG
2984 LogMessage("log query: %s", sQuery);
2985 #endif
2986
2987 SQL_TQuery(gH_BanDatabase, DB_Callback_CTBan, sQuery, iClient);
2988
2989 LogMessage("Console has issued a CT ban on %N (%s) for %d.", iClient, sTargetAuthID, iBanTime);
2990 }
2991
2992 // check if there is a time
2993 if (iBanTime > CTBAN_PERM_BAN_LENGTH)
2994 {
2995 ShowActivity2(iAdmin, "", g_sChatBanner, "Temporary CT Ban and Reason", iClient, iBanTime, sReason);
2996 // save in local quick-access array
2997 PushArrayCell(gA_TimedBanLocalList, iClient);
2998 gA_LocalTimeRemaining[iClient] = iBanTime;
2999
3000 // save in long-term database (already guaranteed to run only once per steam ID)
3001 switch (g_eDatabaseType)
3002 {
3003 case e_SQLite:
3004 {
3005 Format(sQuery, sizeof(sQuery), CTBAN_QUERY_TIME_INSERT_SQLITE, g_sTimesTableName, sTargetAuthID, iBanTime);
3006 }
3007 default:
3008 {
3009 Format(sQuery, sizeof(sQuery), CTBAN_QUERY_TIME_INSERT_MYSQL, g_sTimesTableName, sTargetAuthID, iBanTime, iBanTime);
3010 }
3011 }
3012
3013 #if defined CTBAN_DEBUG
3014 LogMessage("ctban query: %s", sQuery);
3015 #endif
3016
3017 SQL_TQuery(gH_BanDatabase, DB_Callback_CTBan, sQuery, iClient);
3018 }
3019 else
3020 {
3021 ShowActivity2(iAdmin, "", g_sChatBanner, "Permanent CT Ban and Reason", iClient, sReason);
3022 }
3023
3024 Call_StartForward(g_hFrwd_OnCTBan);
3025 Call_PushCell(iClient);
3026 Call_PushCell(iAdmin);
3027 Call_PushCell(iBanTime);
3028 Call_PushString(sReason);
3029 Call_Finish();
3030}
3031
3032public void DB_Callback_CTBan(Handle hOwner, Handle hCallback, const char[] sError, any iClient)
3033{
3034 if (hCallback == INVALID_HANDLE)
3035 {
3036 LogError("Error writing CTBan to Timed Ban database: %s", sError);
3037 }
3038 else
3039 {
3040 #if defined CTBAN_DEBUG
3041 if (iClient > ZERO && IsClientInGame(iClient))
3042 {
3043 LogMessage("SQL CTBan: Updated database with CT Ban for %N", iClient);
3044 }
3045 #endif
3046 }
3047}
3048
3049public Action Command_Change_CTBan_Time(int iClient, int iArgs)
3050{
3051 if (iArgs != CHANGE_TIME_ARG_TIME)
3052 {
3053 ReplyToCommand(iClient, g_sChatBanner, "Command Usage", "sm_change_ctban_time <player> <time>");
3054 return Plugin_Handled;
3055 }
3056
3057 char sTarget[MAX_TARGET_LENGTH];
3058 GetCmdArg(CHANGE_TIME_ARG_TARGET, sTarget, sizeof(sTarget));
3059
3060 char sClientName[MAX_TARGET_LENGTH];
3061 int aiTargetList[MAXPLAYERS];
3062 int iTargetCount;
3063 bool b_tn_is_ml;
3064 iTargetCount = ProcessTargetString(sTarget, iClient, aiTargetList, MAXPLAYERS, COMMAND_FILTER_NO_MULTI, sClientName, sizeof(sClientName), b_tn_is_ml);
3065 if (iTargetCount < ONE)
3066 {
3067 ReplyToTargetError(iClient, iTargetCount);
3068 }
3069 else
3070 {
3071 int iTarget = aiTargetList[ZERO];
3072 if (GetCTBanStatus(iTarget))
3073 {
3074 char sTime[MAX_TIME_ARG_LENGTH];
3075 GetCmdArg(CHANGE_TIME_ARG_TIME, sTime, sizeof(sTime));
3076
3077 int iTime = StringToInt(sTime);
3078
3079 if (iTime < ZERO)
3080 {
3081 ReplyToCommand(iClient, g_sChatBanner, "Invalid Amount");
3082 }
3083 // check if time is not changing
3084 else if (gA_LocalTimeRemaining[iTarget] == iTime || (gA_LocalTimeRemaining[iTarget] <= ZERO && iTime == ZERO))
3085 {
3086 ReplyToCommand(iClient, g_sChatBanner, "Invalid Amount");
3087 }
3088 else
3089 {
3090 PerformChangeCTBanTime(iTarget, iClient, iTime);
3091 }
3092 }
3093 else
3094 {
3095 ReplyToCommand(iClient, g_sChatBanner, "Not CT Banned", iTarget);
3096 }
3097 }
3098
3099 return Plugin_Handled;
3100}
3101
3102void PerformChangeCTBanTime(int iTarget, int iClient, int iTime)
3103{
3104 // 3 types of possible actions depending on the existing and new ban type
3105 // timed to timed
3106 if (iTime > ZERO && gA_LocalTimeRemaining[iTarget] > ZERO)
3107 {
3108 gA_LocalTimeRemaining[iTarget] = iTime;
3109
3110 ShowActivity2(iClient, "", g_sChatBanner, "Temporary CT Ban", iTarget, iTime);
3111
3112 // if it is a timed to timed change then the values will be cached on client disconnect like normal
3113 }
3114 // timed to perm
3115 else if (iTime == ZERO && gA_LocalTimeRemaining[iTarget] > ZERO)
3116 {
3117 gA_LocalTimeRemaining[iTarget] = iTime;
3118
3119 // check if they were in the timed array
3120 int iBannedArrayIndex = FindValueInArray(gA_TimedBanLocalList, iTarget);
3121 if (iBannedArrayIndex != VALUE_NOT_FOUND_IN_ARRAY)
3122 {
3123 // remove them from the local array
3124 RemoveFromArray(gA_TimedBanLocalList, iBannedArrayIndex);
3125
3126 char sAuthId[FIELD_AUTHID_MAXLENGTH];
3127 GetClientAuthId(iTarget, AuthId_Steam2, sAuthId, sizeof(sAuthId));
3128
3129 // fix these tables so it will not reset on the next server join
3130 char sQuery[QUERY_MAXLENGTH];
3131 Format(sQuery, sizeof(sQuery), CTBAN_QUERY_TIME_DELETE, g_sTimesTableName, sAuthId);
3132 SQL_TQuery(gH_BanDatabase, DB_Callback_DisconnectAction, sQuery);
3133
3134 switch (g_eDatabaseType)
3135 {
3136 case e_SQLite:
3137 {
3138 Format(sQuery, sizeof(sQuery), CTBAN_QUERY_LOG_TIME_TO_PERM_SQLITE, g_sLogTableName, sAuthId);
3139 }
3140 default:
3141 {
3142 Format(sQuery, sizeof(sQuery), CTBAN_QUERY_LOG_TIME_TO_PERM_MYSQL, g_sLogTableName, sAuthId);
3143 }
3144 }
3145 SQL_TQuery(gH_BanDatabase, DB_Callback_DisconnectAction, sQuery);
3146 }
3147
3148 ShowActivity2(iClient, "", g_sChatBanner, "Permanent CT Ban", iTarget);
3149 }
3150 // perm to timed
3151 else if (iTime > ZERO && gA_LocalTimeRemaining[iTarget] <= ZERO)
3152 {
3153 // save in local quick-access array
3154 PushArrayCell(gA_TimedBanLocalList, iTarget);
3155 gA_LocalTimeRemaining[iTarget] = iTime;
3156
3157 char sAuthId[FIELD_AUTHID_MAXLENGTH];
3158 GetClientAuthId(iTarget, AuthId_Steam2, sAuthId, sizeof(sAuthId));
3159
3160 // save in long-term database (already guaranteed to run only once per steam ID)
3161 char sQuery[QUERY_MAXLENGTH];
3162 switch (g_eDatabaseType)
3163 {
3164 case e_SQLite:
3165 {
3166 Format(sQuery, sizeof(sQuery), CTBAN_QUERY_TIME_INSERT_SQLITE, g_sTimesTableName, sAuthId, iTime);
3167 }
3168 default:
3169 {
3170 Format(sQuery, sizeof(sQuery), CTBAN_QUERY_TIME_INSERT_MYSQL, g_sTimesTableName, sAuthId, iTime, iTime);
3171 }
3172 }
3173 #if defined CTBAN_DEBUG
3174 LogMessage("ctban query: %s", sQuery);
3175 #endif
3176 SQL_TQuery(gH_BanDatabase, DB_Callback_DisconnectAction, sQuery);
3177
3178 switch (g_eDatabaseType)
3179 {
3180 case e_SQLite:
3181 {
3182 Format(sQuery, sizeof(sQuery), CTBAN_QUERY_LOG_PERM_TO_TIME_SQLITE, g_sLogTableName, iTime, iTime, sAuthId);
3183 }
3184 default:
3185 {
3186 Format(sQuery, sizeof(sQuery), CTBAN_QUERY_LOG_PERM_TO_TIME_MYSQL, g_sLogTableName, iTime, iTime, sAuthId);
3187 }
3188 }
3189 SQL_TQuery(gH_BanDatabase, DB_Callback_DisconnectAction, sQuery);
3190
3191 ShowActivity2(iClient, "", g_sChatBanner, "Temporary CT Ban", iTarget, iTime);
3192 }
3193}
3194
3195public Action Command_CTBanList(int iClient, int iArgs)
3196{
3197 // console user
3198 if (!iClient)
3199 {
3200 for (int iIndex = ONE; iIndex <= MaxClients; iIndex++)
3201 {
3202 if (IsClientInGame(iIndex))
3203 {
3204 if (GetCTBanStatus(iIndex))
3205 {
3206 if (gA_LocalTimeRemaining[iIndex] <= ZERO)
3207 {
3208 ReplyToCommand(iClient, g_sChatBanner, "Permanent CT Ban", iIndex);
3209 }
3210 else
3211 {
3212 ReplyToCommand(iClient, g_sChatBanner, "Temporary CT Ban", iIndex, gA_LocalTimeRemaining[iIndex]);
3213 }
3214 }
3215 }
3216 }
3217 }
3218 // regular in-game player
3219 else
3220 {
3221 // check if client is allowed to use the command
3222 AdminId clientAdminId = GetUserAdmin(iClient);
3223 char sFlags[MAX_ADMINFLAGS_LENGTH];
3224 GetConVarString(gH_Cvar_CheckCTBans_Flags, sFlags, sizeof(sFlags));
3225 int iAdminFlags = ReadFlagString(sFlags);
3226
3227 #if defined CTBAN_DEBUG
3228 LogMessage("Flag string %s and value %d and client effective %d", sFlags, iAdminFlags, GetAdminFlags(clientAdminId, Access_Effective));
3229 #endif
3230
3231 // length of 0 means they want everyone to have access to this
3232 if (strlen(sFlags) == ZERO)
3233 {
3234 DisplayCTBannedPlayerMenu(iClient, e_CTBanList);
3235 }
3236 // if the player has no admin access
3237 // iAdminFlags bitstring & client's bitstring will leave a logic TRUE if there is overlap
3238 else if (clientAdminId == INVALID_ADMIN_ID || !(iAdminFlags & GetAdminFlags(clientAdminId, Access_Effective)))
3239 {
3240 ReplyToCommand(iClient, g_sChatBanner, "No Access");
3241 }
3242 // they are an admin and they have effective flag access
3243 else
3244 {
3245 DisplayCTBannedPlayerMenu(iClient, e_CTBanList);
3246 }
3247 }
3248
3249 return Plugin_Handled;
3250}
3251
3252public Action Command_IsBanned(int iClient, int iArgs)
3253{
3254 char sTarget[MAX_TARGET_LENGTH];
3255 GetCmdArg(ISBANNED_ARG_TARGET, sTarget, sizeof(sTarget));
3256
3257 char sClientName[MAX_TARGET_LENGTH];
3258 int aiTargetList[MAXPLAYERS];
3259 int iTargetCount;
3260 bool b_tn_is_ml;
3261 iTargetCount = ProcessTargetString(sTarget, iClient, aiTargetList, MAXPLAYERS, COMMAND_FILTER_NO_MULTI | COMMAND_FILTER_NO_IMMUNITY, sClientName, sizeof(sClientName), b_tn_is_ml);
3262 int iTarget = aiTargetList[ZERO];
3263
3264 // Console
3265 if (!iClient)
3266 {
3267 if (!iArgs)
3268 {
3269 ReplyToCommand(iClient, g_sChatBanner, "Command Usage", "sm_isbanned <player>");
3270 }
3271 else
3272 {
3273 if (iTargetCount < ONE)
3274 {
3275 ReplyToTargetError(iClient, iTargetCount);
3276 }
3277 else
3278 {
3279 ProcessIsBannedTarget(iTarget, iClient);
3280 }
3281 }
3282 return Plugin_Handled;
3283 }
3284
3285 // check if client is allowed to use the command
3286 AdminId clientAdminId = GetUserAdmin(iClient);
3287 char sFlags[MAX_ADMINFLAGS_LENGTH];
3288 GetConVarString(gH_Cvar_CheckCTBans_Flags, sFlags, sizeof(sFlags));
3289
3290 int iAdminFlags = ReadFlagString(sFlags);
3291
3292 #if defined CTBAN_DEBUG
3293 LogMessage("Flag string %s and value %d and client effective %d", sFlags, iAdminFlags, GetAdminFlags(clientAdminId, Access_Effective));
3294 #endif
3295
3296 // length of 0 means they want everyone to have access to this
3297 if (strlen(sFlags) == ZERO)
3298 {
3299 if (!iArgs)
3300 {
3301 // automatically target self
3302 ProcessIsBannedTarget(iClient, iClient);
3303 }
3304 else
3305 {
3306 if (iTargetCount < ONE)
3307 {
3308 ReplyToTargetError(iClient, iTargetCount);
3309 }
3310 else
3311 {
3312 ProcessIsBannedTarget(iTarget, iClient);
3313 }
3314 }
3315 }
3316 // if the player has no admin access
3317 // iAdminFlags bitstring & client's bitstring will leave a logic TRUE if there is overlap
3318 else if (clientAdminId == INVALID_ADMIN_ID || !(iAdminFlags & GetAdminFlags(clientAdminId, Access_Effective)))
3319 {
3320 // check if self-targeting allowed
3321 if (GetConVarBool(gH_Cvar_IsBanned_Self))
3322 {
3323 if (!iArgs)
3324 {
3325 // automatically target self
3326 ProcessIsBannedTarget(iClient, iClient);
3327 }
3328 else
3329 {
3330 // check if they target themselves
3331 if (iTargetCount < ONE)
3332 {
3333 ReplyToTargetError(iClient, iTargetCount);
3334 }
3335 else if (iTarget != iClient)
3336 {
3337 ReplyToCommand(iClient, g_sChatBanner, "No Access");
3338 }
3339 // target is the calling client
3340 else
3341 {
3342 ProcessIsBannedTarget(iTarget, iClient);
3343 }
3344 }
3345 }
3346 else
3347 {
3348 ReplyToCommand(iClient, g_sChatBanner, "No Access");
3349 }
3350 }
3351 // they are an admin and they have effective flag access
3352 else
3353 {
3354 if (!iArgs)
3355 {
3356 ReplyToCommand(iClient, g_sChatBanner, "Command Usage", "sm_isbanned <player>");
3357 }
3358 else
3359 {
3360 if (iTargetCount < ONE)
3361 {
3362 ReplyToTargetError(iClient, iTargetCount);
3363 }
3364 else
3365 {
3366 ProcessIsBannedTarget(iTarget, iClient);
3367 }
3368 }
3369 }
3370
3371 return Plugin_Handled;
3372}
3373
3374void ProcessIsBannedTarget(int iTarget, int iCaller)
3375{
3376 #if defined CTBAN_DEBUG
3377 LogMessage("Processing IsBanned on %N by %N", iTarget, iCaller);
3378 #endif
3379
3380 if(iTarget > ZERO && iTarget <= MaxClients && IsClientInGame(iTarget))
3381 {
3382 if (GetCTBanStatus(iTarget, iCaller))
3383 {
3384 // grab perp steam id
3385 char sPerpSteamID[FIELD_AUTHID_MAXLENGTH];
3386 GetClientAuthId(iTarget, AuthId_Steam2, sPerpSteamID, sizeof(sPerpSteamID));
3387
3388 char sQuery[QUERY_MAXLENGTH];
3389 Format(sQuery, sizeof(sQuery), CTBAN_QUERY_LOG_ISBANNED, g_sLogTableName, sPerpSteamID);
3390
3391 #if defined CTBAN_DEBUG
3392 LogMessage("isbanned query: %s", sQuery);
3393 #endif
3394
3395 Handle hDataPack = CreateDataPack();
3396 // perp SteamID
3397 WritePackString(hDataPack, sPerpSteamID);
3398 // current client who asked for isbanned info
3399 WritePackCell(hDataPack, iCaller);
3400 // target index
3401 WritePackCell(hDataPack, iTarget);
3402
3403 SQL_TQuery(gH_BanDatabase, DB_Callback_IsBanned, sQuery, hDataPack);
3404 }
3405 else
3406 {
3407 if (iCaller != CALLER_NATIVE)
3408 {
3409 ReplyToCommand(iCaller, g_sChatBanner, "Not CT Banned", iTarget);
3410 }
3411 else
3412 {
3413 ThrowNativeError(SP_ERROR_NATIVE, g_sChatBanner, "Not CT Banned", iTarget);
3414 }
3415 }
3416 }
3417 else
3418 {
3419 if (iCaller != CALLER_NATIVE)
3420 {
3421 ReplyToCommand(iCaller, g_sChatBanner, "Unable to target");
3422 }
3423 else
3424 {
3425 ThrowNativeError(SP_ERROR_NATIVE, g_sChatBanner, "Unable to target");
3426 }
3427 }
3428}
3429
3430public void DB_Callback_IsBanned(Handle hOwner, Handle hCallback, const char[] sError, any hDataPack)
3431{
3432 if (hCallback == INVALID_HANDLE)
3433 {
3434 LogError("Error in IsBanned query: %s", sError);
3435 CloseHandle(hDataPack);
3436 }
3437 else
3438 {
3439 ResetPack(hDataPack);
3440 char sPerpAuthID[FIELD_AUTHID_MAXLENGTH];
3441 ReadPackString(hDataPack, sPerpAuthID, sizeof(sPerpAuthID));
3442 int iCaller = ReadPackCell(hDataPack);
3443 int iTarget = ReadPackCell(hDataPack);
3444 CloseHandle(hDataPack);
3445
3446 int iRowCount = SQL_GetRowCount(hCallback);
3447 if (iRowCount > ONE || iRowCount < ZERO)
3448 {
3449 LogError("%d rows returned on LIMIT 1 query: %s", iRowCount, sError);
3450 }
3451 else if (!iRowCount)
3452 {
3453 #if defined CTBAN_DEBUG
3454 LogMessage("Row count is 0 for IsBanned Query!");
3455 #endif
3456
3457 if (iCaller == CALLER_NATIVE)
3458 {
3459 // Have to use incomplete information because the row is missing from the database table
3460 Call_StartForward(g_hFrwd_CTBanInfo);
3461 Call_PushCell(false);
3462 Call_PushCell(iTarget);
3463 Call_PushCell(gA_LocalTimeRemaining[iTarget]);
3464 Call_PushCell(CALLER_NATIVE);
3465 Call_PushString("Invalid");
3466 Call_PushString("Invalid");
3467 Call_Finish();
3468 }
3469 else if (gA_LocalTimeRemaining[iTarget] <= ZERO)
3470 {
3471 if (!iCaller)
3472 {
3473 PrintToServer(g_sChatBanner, "Permanent CT Ban", iTarget);
3474 }
3475 else
3476 {
3477 PrintToChat(iCaller, g_sChatBanner, "Permanent CT Ban", iTarget);
3478 }
3479 }
3480 else
3481 {
3482 if (!iCaller)
3483 {
3484 PrintToServer(g_sChatBanner, "Temporary CT Ban", iTarget, gA_LocalTimeRemaining[iTarget]);
3485 }
3486 else
3487 {
3488 PrintToChat(iCaller, g_sChatBanner, "Temporary CT Ban", iTarget, gA_LocalTimeRemaining[iTarget]);
3489 }
3490 }
3491 }
3492 // Rows are exactly 1
3493 else
3494 {
3495 SQL_FetchRow(hCallback);
3496 int iTimeStamp = SQL_FetchInt(hCallback, ISBANNED_CB_FIELD_TIMESTAMP);
3497 char sAdminName[FIELD_NAME_MAXLENGTH];
3498 SQL_FetchString(hCallback, ISBANNED_CB_FIELD_ADMINNAME, sAdminName, sizeof(sAdminName));
3499 char sReason[FIELD_REASON_MAXLENGTH];
3500 SQL_FetchString(hCallback, ISBANNED_CB_FIELD_REASON, sReason, sizeof(sReason));
3501 #if defined CTBAN_DEBUG
3502 LogMessage("SQL ISBanned: admin %s banned with timestamp %d for reason %s", sAdminName, iTimeStamp, sReason);
3503 #endif
3504
3505 char sTimeBanned[MAX_TIME_INFO_STR_LENGTH];
3506 FormatTime(sTimeBanned, sizeof(sTimeBanned), NULL_STRING, iTimeStamp);
3507
3508 #if defined CTBAN_DEBUG
3509 LogMessage("target %N, admin banning %s, when banned %s, timeleft %d", iTarget, sAdminName, sTimeBanned, gA_LocalTimeRemaining[iTarget]);
3510 #endif
3511
3512 // check if we need to fire a forward from a native call
3513 if (iCaller == CALLER_NATIVE)
3514 {
3515 Call_StartForward(g_hFrwd_CTBanInfo);
3516 Call_PushCell(true);
3517 Call_PushCell(iTarget);
3518 Call_PushCell(gA_LocalTimeRemaining[iTarget]);
3519 Call_PushCell(iTimeStamp);
3520 Call_PushString(sAdminName);
3521 Call_PushString(sReason);
3522 Call_Finish();
3523 }
3524 // find the time if any
3525 else if (gA_LocalTimeRemaining[iTarget] <= ZERO)
3526 {
3527 if (!iCaller)
3528 {
3529 PrintToServer(g_sChatBanner, "IsBanned Permanent", iTarget, sAdminName, sTimeBanned, sReason);
3530 }
3531 else
3532 {
3533 PrintToChat(iCaller, g_sChatBanner, "IsBanned Permanent", iTarget, sAdminName, sTimeBanned, sReason);
3534 }
3535 }
3536 else
3537 {
3538 if (!iCaller)
3539 {
3540 PrintToServer(g_sChatBanner, "IsBanned Temporary", iTarget, gA_LocalTimeRemaining[iTarget], sAdminName, sTimeBanned, sReason);
3541 }
3542 else
3543 {
3544 PrintToChat(iCaller, g_sChatBanner, "IsBanned Temporary", iTarget, gA_LocalTimeRemaining[iTarget], sAdminName, sTimeBanned, sReason);
3545 }
3546 }
3547 }
3548 }
3549}
3550
3551public Action Command_Offline_IsBanned(int iClient, int iArgs)
3552{
3553 char sPerpSteamID[FIELD_AUTHID_MAXLENGTH];
3554 GetCmdArgString(sPerpSteamID, sizeof(sPerpSteamID));
3555 TrimString(sPerpSteamID);
3556
3557 if (IsAuthIdConnected(sPerpSteamID))
3558 {
3559 ReplyToCommand(iClient, g_sChatBanner, "Unable to target");
3560 }
3561 else
3562 {
3563 ProcessIsBannedOffline(iClient, sPerpSteamID);
3564 }
3565
3566 return Plugin_Handled;
3567}
3568
3569void ProcessIsBannedOffline(int iCaller, char[] sPerpAuthID)
3570{
3571 char sEscapedPerpSteamID[MAX_SAFE_ESCAPE_QUERY(FIELD_NAME_MAXLENGTH)];
3572 SQL_EscapeString(gH_BanDatabase, sPerpAuthID, sEscapedPerpSteamID, sizeof(sEscapedPerpSteamID));
3573
3574 char sQuery[QUERY_MAXLENGTH];
3575 Format(sQuery, sizeof(sQuery), CTBAN_QUERY_LOG_ISBANNED_OFFLINE, g_sLogTableName, sEscapedPerpSteamID);
3576
3577 #if defined CTBAN_DEBUG
3578 LogMessage("offline isbanned query: %s", sQuery);
3579 #endif
3580
3581 Handle hDataPack = CreateDataPack();
3582 // perp SteamID
3583 WritePackString(hDataPack, sPerpAuthID);
3584 // current client who asked for isbanned info
3585 WritePackCell(hDataPack, iCaller);
3586
3587 SQL_TQuery(gH_BanDatabase, DB_Callback_Offline_IsBanned, sQuery, hDataPack);
3588}
3589
3590public void DB_Callback_Offline_IsBanned(Handle hOwner, Handle hCallback, const char[] sError, any hOfflineIsBannedPack)
3591{
3592 if (hCallback == INVALID_HANDLE)
3593 {
3594 LogError("Error in Offline IsBanned query: %s", sError);
3595 }
3596 else
3597 {
3598 ResetPack(hOfflineIsBannedPack);
3599 char sPerpAuthID[FIELD_AUTHID_MAXLENGTH];
3600 ReadPackString(hOfflineIsBannedPack, sPerpAuthID, sizeof(sPerpAuthID));
3601 int iClient = ReadPackCell(hOfflineIsBannedPack);
3602 CloseHandle(hOfflineIsBannedPack);
3603
3604 int iRowCount = SQL_GetRowCount(hCallback);
3605 if (iRowCount != ONE)
3606 {
3607 if (iClient == CALLER_NATIVE)
3608 {
3609 Call_StartForward(g_hFrwd_CTBanInfoOffline);
3610 Call_PushCell(false);
3611 Call_PushString(sPerpAuthID);
3612 Call_PushCell(CALLER_NATIVE);
3613 Call_PushCell(CALLER_NATIVE);
3614 Call_PushString("Invalid");
3615 Call_PushString("Invalid");
3616 Call_PushString("Invalid");
3617 Call_Finish();
3618 }
3619 else if (!iClient)
3620 {
3621 PrintToServer(g_sChatBanner, "No matching client");
3622 }
3623 else
3624 {
3625 PrintToChat(iClient, g_sChatBanner, "No matching client");
3626 }
3627 }
3628 else
3629 {
3630 SQL_FetchRow(hCallback);
3631 int timestamp = SQL_FetchInt(hCallback, ISBANNED_OFF_CB_FIELD_TIMESTAMP);
3632 char sAdminName[FIELD_NAME_MAXLENGTH];
3633 SQL_FetchString(hCallback, ISBANNED_OFF_CB_FIELD_ADMINNAME, sAdminName, sizeof(sAdminName));
3634 char sReason[FIELD_REASON_MAXLENGTH];
3635 SQL_FetchString(hCallback, ISBANNED_OFF_CB_FIELD_REASON, sReason, sizeof(sReason));
3636 int timeleft = SQL_FetchInt(hCallback, ISBANNED_OFF_CB_FIELD_TIMELEFT);
3637 char sPerpName[FIELD_NAME_MAXLENGTH];
3638 SQL_FetchString(hCallback, ISBANNED_OFF_CB_FIELD_PERPNAME, sPerpName, sizeof(sPerpName));
3639
3640 char sTimeBanned[MAX_TIME_INFO_STR_LENGTH];
3641 FormatTime(sTimeBanned, sizeof(sTimeBanned), NULL_STRING, timestamp);
3642
3643 #if defined CTBAN_DEBUG
3644 LogMessage("target name %s, admin banning %s, when banned %s, timeleft %d", sPerpName, sAdminName, sTimeBanned, timeleft);
3645 #endif
3646
3647 if (iClient == CALLER_NATIVE)
3648 {
3649 Call_StartForward(g_hFrwd_CTBanInfoOffline);
3650 Call_PushCell(true);
3651 Call_PushString(sPerpAuthID);
3652 Call_PushCell(timeleft);
3653 Call_PushCell(timestamp);
3654 Call_PushString(sAdminName);
3655 Call_PushString(sReason);
3656 Call_PushString(sPerpName);
3657 Call_Finish();
3658 }
3659 else if (timeleft <= ZERO)
3660 {
3661 if (!iClient)
3662 {
3663 PrintToServer(g_sChatBanner, "IsBanned Permanent String Name", sPerpName, sAdminName, sTimeBanned, sReason);
3664 }
3665 else
3666 {
3667 PrintToChat(iClient, g_sChatBanner, "IsBanned Permanent String Name", sPerpName, sAdminName, sTimeBanned, sReason);
3668 }
3669 }
3670 else
3671 {
3672 if (!iClient)
3673 {
3674 PrintToServer(g_sChatBanner, "IsBanned Temporary String Name", sPerpName, timeleft, sAdminName, sTimeBanned, sReason);
3675 }
3676 else
3677 {
3678 PrintToChat(iClient, g_sChatBanner, "IsBanned Temporary String Name", sPerpName, timeleft, sAdminName, sTimeBanned, sReason);
3679 }
3680 }
3681 }
3682 }
3683}
3684
3685public Action Command_CheckJoin(int iClient, const char[] sCommand, int iArgs)
3686{
3687 // 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)
3688 if(!iClient || !IsClientInGame(iClient) || IsFakeClient(iClient) || !AreClientCookiesCached(iClient))
3689 {
3690 return Plugin_Continue;
3691 }
3692
3693 // Get the target team
3694 char sJoinTeamString[MAX_JOINTEAM_ARG_LENGTH];
3695 GetCmdArg(JOINTEAM_ARG_TEAM_STRING, sJoinTeamString, sizeof(sJoinTeamString));
3696 int iTargetTeam = StringToInt(sJoinTeamString);
3697
3698 int iBanStatus = GetCTBanStatus(iClient);
3699
3700 // check for an active ban to send a message
3701 if ((iTargetTeam == CS_TEAM_SPECTATOR || iTargetTeam == CS_TEAM_T) && iBanStatus)
3702 {
3703 // display them a message about the ban
3704 int iTimeBanned = GetClientCookieTime(iClient, g_CT_Cookie);
3705 char sTimeBanned[MAX_TIME_INFO_STR_LENGTH];
3706 FormatTime(sTimeBanned, sizeof(sTimeBanned), NULL_STRING, iTimeBanned);
3707 char sJoinBanMsg[MAX_JOIN_BAN_MSG_LENGTH];
3708 GetConVarString(gH_Cvar_JoinBanMessage, sJoinBanMsg, sizeof(sJoinBanMsg));
3709 PrintHintText(iClient, "%t", "Last CT Banned On", sTimeBanned, sJoinBanMsg);
3710
3711 if (GetConVarBool(gH_Cvar_IsBanned_Self))
3712 {
3713 ProcessIsBannedTarget(iClient, iClient);
3714 }
3715 }
3716 // otherwise they joined CT or auto-select and are banned
3717 else if (iBanStatus)
3718 {
3719 if(strcmp(gS_SoundPath, ""))
3720 {
3721 char sPlayCommand[PLATFORM_MAX_PATH + PLAY_COMMAND_STRING_LENGTH];
3722 Format(sPlayCommand, sizeof(sPlayCommand), "%s%s", PLAY_COMMAND_STRING, gS_SoundPath);
3723 ClientCommand(iClient, sPlayCommand);
3724 }
3725 PrintToChat(iClient, g_sChatBanner, "Enforcing CT Ban");
3726
3727 // if they are already on the Terrorist team then they don't need to pick anything again
3728 if (GetClientTeam(iClient) != CS_TEAM_T)
3729 {
3730 UTIL_TeamMenu(iClient);
3731 }
3732
3733 return Plugin_Stop;
3734 }
3735
3736 return Plugin_Continue;
3737}
3738
3739// This helper procedure will re-display the team join menu
3740// and is equivalent to what ClientCommand(client, "chooseteam") did in the past
3741void UTIL_TeamMenu(int iClient)
3742{
3743 int aiClients[ONE];
3744 Handle hBfWritePack;
3745 aiClients[ZERO] = iClient;
3746 hBfWritePack = StartMessage("VGUIMenu", aiClients, ONE);
3747
3748 if (GetUserMessageType() == UM_Protobuf)
3749 {
3750 PbSetString(hBfWritePack, "name", "team");
3751 PbSetBool(hBfWritePack, "show", true);
3752 }
3753 else
3754 {
3755 BfWriteString(hBfWritePack, "team"); // panel name
3756 BfWriteByte(hBfWritePack, ONE); // bShow
3757 BfWriteByte(hBfWritePack, ZERO); // count
3758 }
3759
3760 EndMessage();
3761}
3762
3763// figure out if we can use the handy native SetAuthIdCookie
3764bool IsSetAuthIdNativePresent()
3765{
3766 if (GetFeatureStatus(FeatureType_Native, "SetAuthIdCookie") == FeatureStatus_Available)
3767 {
3768 return true;
3769 }
3770 return false;
3771}
3772
3773int GetCTBanStatus(int iClient, int iCaller = CALLER_DO_NOT_REPLY)
3774{
3775 int iCTBanStatus = ZERO;
3776
3777 if (AreClientCookiesCached(iClient))
3778 {
3779 char sCookie[MAX_COOKIE_STR_LENGTH];
3780 GetClientCookie(iClient, g_CT_Cookie, sCookie, sizeof(sCookie));
3781 iCTBanStatus = StringToInt(sCookie);
3782 }
3783 else
3784 {
3785 if (iCaller >= ZERO)
3786 {
3787 ReplyToCommand(iCaller, g_sChatBanner, "Cookie Status Unavailable");
3788 }
3789 }
3790
3791 return iCTBanStatus;
3792}
3793
3794void EnforceCTBan(int iClient)
3795{
3796 if (IsPlayerAlive(iClient))
3797 {
3798 // strip their weapons so they cannot gunplant after death
3799 StripAllWeapons(iClient);
3800
3801 ForcePlayerSuicide(iClient);
3802 }
3803
3804 ChangeClientTeam(iClient, CS_TEAM_T);
3805
3806 if (GetConVarBool(gH_Cvar_Respawn))
3807 {
3808 CS_RespawnPlayer(iClient);
3809 }
3810
3811 PrintToChat(iClient, g_sChatBanner, "Enforcing CT Ban");
3812}
3813
3814#if !defined _Hosties_Included_
3815 // From hosties.inc on Beta branch (20 Aug 2017)
3816 stock void StripAllWeapons(int iClient)
3817 {
3818 int iWeaponIndex = INVALID_WEAPON;
3819 for (int iLoopIndex = CS_SLOT_PRIMARY; iLoopIndex < CS_SLOT_GRENADE + ONE; iLoopIndex++)
3820 {
3821 iWeaponIndex = INVALID_WEAPON;
3822 while ((iWeaponIndex = GetPlayerWeaponSlot(iClient, iLoopIndex)) != INVALID_WEAPON)
3823 {
3824 RemovePlayerItem(iClient, iWeaponIndex);
3825 AcceptEntityInput(iWeaponIndex, "Kill");
3826 }
3827 }
3828 }
3829#endif
3830
3831#if !defined _CTBan_Included_
3832 stock int IsAuthIdConnected(char[] sAuthID)
3833 {
3834 char sIndexAuthID[FIELD_AUTHID_MAXLENGTH];
3835 for (int iIndex = ONE; iIndex <= MaxClients; iIndex++)
3836 {
3837 if (IsClientInGame(iIndex))
3838 {
3839 GetClientAuthId(iIndex, AuthId_Steam2, sIndexAuthID, sizeof(sIndexAuthID));
3840 if (StrEqual(sAuthID, sIndexAuthID))
3841 {
3842 return iIndex;
3843 }
3844 }
3845 }
3846
3847 return ZERO;
3848 }
3849
3850 stock void ParseCTBanReasonsFile(Handle hReasonsArray)
3851 {
3852 ClearArray(hReasonsArray);
3853
3854 char sPathReasons[PLATFORM_MAX_PATH];
3855 BuildPath(Path_SM, sPathReasons, sizeof(sPathReasons), "configs/ctban_reasons.ini");
3856 Handle hReasonsFile = OpenFile(sPathReasons, "r");
3857
3858 if (hReasonsFile != null)
3859 {
3860 char sReasonsLine[FIELD_REASON_MAXLENGTH];
3861
3862 while (ReadFileLine(hReasonsFile, sReasonsLine, sizeof(sReasonsLine)))
3863 {
3864 PushArrayString(hReasonsArray, sReasonsLine);
3865 }
3866 }
3867
3868 CloseHandle(hReasonsFile);
3869 }
3870
3871 stock Handle ParseCTBanLengthsFile(Handle hKeyValues)
3872 {
3873 if (hKeyValues != INVALID_HANDLE)
3874 {
3875 CloseHandle(hKeyValues);
3876 }
3877
3878 hKeyValues = CreateKeyValues("length");
3879
3880 char sPathLengths[PLATFORM_MAX_PATH];
3881 BuildPath(Path_SM, sPathLengths, sizeof(sPathLengths), "configs/ctban_times.ini");
3882
3883 if (FileToKeyValues(hKeyValues, sPathLengths))
3884 {
3885 KvRewind(hKeyValues);
3886 }
3887 else
3888 {
3889 CloseHandle(hKeyValues);
3890 return INVALID_HANDLE;
3891 }
3892
3893 return hKeyValues;
3894 }
3895
3896 stock void SetCTBanChatBanner(EngineVersion e_EngineVersion, char sChatBanner[MAX_CHAT_BANNER_LENGTH])
3897 {
3898 switch (e_EngineVersion)
3899 {
3900 case Engine_CSS, Engine_TF2:
3901 {
3902 sChatBanner = "[\x0799CCFFCTBAN\x01] \x07FFD700%t";
3903 }
3904 case Engine_CSGO:
3905 {
3906 sChatBanner = "[\x0BCTBAN\x01] \x10%t";
3907 }
3908 default:
3909 {
3910 SetFailState("Game engine is not supported.");
3911 }
3912 }
3913 }
3914#endif
3915
3916/*
3917 [CS:S/CS:GO] CT Bans
3918 by: databomb
3919*/