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