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