· 8 years ago · May 26, 2018, 12:00 AM
1// *************************************************************************
2// This file is part of SourceBans++.
3//
4// Copyright (C) 2014-2016 SourceBans++ Dev Team <https://github.com/sbpp>
5//
6// SourceBans++ is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, per version 3 of the License.
9//
10// SourceBans++ is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with SourceBans++. If not, see <http://www.gnu.org/licenses/>.
17//
18// This file is based off work(s) covered by the following copyright(s):
19//
20// SourceBans 1.4.11
21// Copyright (C) 2007-2015 SourceBans Team - Part of GameConnect
22// Licensed under GNU GPL version 3, or later.
23// Page: <http://www.sourcebans.net/> - <https://github.com/GameConnect/sourcebansv1>
24//
25// *************************************************************************
26
27#pragma semicolon 1
28#include <sourcemod>
29#include <sourcebans>
30
31#undef REQUIRE_PLUGIN
32#include <adminmenu>
33#tryinclude <updater>
34
35#define SB_VERSION "1.6.3-PRE"
36#define SBR_VERSION "1.6.3-PRE"
37
38#if defined _updater_included
39#define UPDATE_URL "https://sbpp.github.io/updater/updatefile.txt"
40#endif
41
42//GLOBAL DEFINES
43#define YELLOW 0x01
44#define NAMECOLOR 0x02
45#define TEAMCOLOR 0x03
46#define GREEN 0x04
47
48#define DISABLE_ADDBAN 1
49#define DISABLE_UNBAN 2
50
51#define FLAG_LETTERS_SIZE 26
52
53//#define DEBUG
54
55enum State/* ConfigState */
56{
57 ConfigStateNone = 0,
58 ConfigStateConfig,
59 ConfigStateReasons,
60 ConfigStateHacking,
61 ConfigStateTime
62}
63
64new g_BanTarget[MAXPLAYERS + 1] = { -1, ... };
65new g_BanTime[MAXPLAYERS + 1] = { -1, ... };
66
67new State:ConfigState;
68new Handle:ConfigParser;
69
70new Handle:hTopMenu = INVALID_HANDLE;
71
72new const String:Prefix[] = "[SourceBans++] ";
73
74new String:ServerIp[24];
75new String:ServerPort[7];
76new String:DatabasePrefix[10] = "sb";
77new String:WebsiteAddress[128];
78
79/* Admin Stuff*/
80new AdminCachePart:loadPart;
81new bool:loadAdmins;
82new bool:loadGroups;
83new bool:loadOverrides;
84new curLoading = 0;
85new AdminFlag:g_FlagLetters[FLAG_LETTERS_SIZE];
86
87/* Admin KeyValues */
88new String:groupsLoc[128];
89new String:adminsLoc[128];
90new String:overridesLoc[128];
91
92/* Cvar handle*/
93new Handle:CvarHostIp;
94new Handle:CvarPort;
95
96/* Database handle */
97new Handle:DB;
98new Handle:SQLiteDB;
99
100/* Menu file globals */
101new Handle:TimeMenuHandle;
102new Handle:ReasonMenuHandle;
103new Handle:HackingMenuHandle;
104
105/* Datapack and Timer handles */
106new Handle:PlayerRecheck[MAXPLAYERS + 1] = { INVALID_HANDLE, ... };
107new Handle:PlayerDataPack[MAXPLAYERS + 1] = { INVALID_HANDLE, ... };
108
109/* Player ban check status */
110new bool:PlayerStatus[MAXPLAYERS + 1];
111
112/* Disable of addban and unban */
113new CommandDisable;
114new bool:backupConfig = true;
115new bool:enableAdmins = true;
116
117/* Require a lastvisited from SB site */
118new bool:requireSiteLogin = false;
119
120/* Log Stuff */
121new String:logFile[256];
122
123/* Own Chat Reason */
124new g_ownReasons[MAXPLAYERS + 1] = { false, ... };
125
126new Float:RetryTime = 15.0;
127new ProcessQueueTime = 5;
128new bool:LateLoaded;
129new bool:AutoAdd;
130new bool:g_bConnecting = false;
131
132new serverID = -1;
133
134new Handle:g_hFwd_OnBanAdded;
135
136public Plugin:myinfo =
137{
138 name = "SourceBans++: Main Plugin",
139 author = "SourceBans Development Team, SourceBans++ Dev Team",
140 description = "Advanced ban management for the Source engine",
141 version = SBR_VERSION,
142 url = "https://sbpp.github.io"
143};
144
145#if SOURCEMOD_V_MAJOR >= 1 && SOURCEMOD_V_MINOR >= 3
146public APLRes:AskPluginLoad2(Handle:myself, bool:late, String:error[], err_max)
147#else
148public bool:AskPluginLoad(Handle:myself, bool:late, String:error[], err_max)
149#endif
150{
151 RegPluginLibrary("sourcebans++");
152 CreateNative("SBBanPlayer", Native_SBBanPlayer);
153 CreateNative("SourceBans_BanPlayer", Native_SBBanPlayer);
154
155 g_hFwd_OnBanAdded = CreateGlobalForward("SourceBans_OnBanPlayer", ET_Ignore, Param_Cell, Param_Cell, Param_Cell, Param_String);
156
157 LateLoaded = late;
158
159 #if SOURCEMOD_V_MAJOR >= 1 && SOURCEMOD_V_MINOR >= 3
160 return APLRes_Success;
161 #else
162 return true;
163 #endif
164}
165
166public OnPluginStart()
167{
168 LoadTranslations("common.phrases");
169 LoadTranslations("plugin.basecommands");
170 LoadTranslations("sourcebans.phrases");
171 LoadTranslations("basebans.phrases");
172 loadAdmins = loadGroups = loadOverrides = false;
173
174 CvarHostIp = FindConVar("hostip");
175 CvarPort = FindConVar("hostport");
176 CreateConVar("sb_version", SB_VERSION, _, FCVAR_SPONLY | FCVAR_REPLICATED | FCVAR_NOTIFY);
177 CreateConVar("sbr_version", SBR_VERSION, _, FCVAR_SPONLY | FCVAR_REPLICATED | FCVAR_NOTIFY);
178 RegServerCmd("sm_rehash", sm_rehash, "Reload SQL admins");
179 RegAdminCmd("sm_ban", CommandBan, ADMFLAG_BAN, "sm_ban <#userid|name> <minutes|0> [reason]", "sourcebans");
180 RegAdminCmd("sm_banip", CommandBanIp, ADMFLAG_BAN, "sm_banip <ip|#userid|name> <time> [reason]", "sourcebans");
181 RegAdminCmd("sm_addban", CommandAddBan, ADMFLAG_RCON, "sm_addban <time> <steamid> [reason]", "sourcebans");
182 RegAdminCmd("sm_unban", CommandUnban, ADMFLAG_UNBAN, "sm_unban <steamid|ip> [reason]", "sourcebans");
183 RegAdminCmd("sb_reload",
184 _CmdReload,
185 ADMFLAG_RCON,
186 "Reload sourcebans config and ban reason menu options",
187 "sourcebans");
188
189 RegConsoleCmd("say", ChatHook);
190 RegConsoleCmd("say_team", ChatHook);
191
192 if ((TimeMenuHandle = CreateMenu(MenuHandler_BanTimeList, MenuAction_Select|MenuAction_Cancel|MenuAction_DrawItem)) != INVALID_HANDLE)
193 {
194 SetMenuPagination(TimeMenuHandle, 8);
195 SetMenuExitBackButton(TimeMenuHandle, true);
196 }
197
198 if ((ReasonMenuHandle = CreateMenu(ReasonSelected)) != INVALID_HANDLE)
199 {
200 SetMenuPagination(ReasonMenuHandle, 8);
201 SetMenuExitBackButton(ReasonMenuHandle, true);
202 }
203
204 if ((HackingMenuHandle = CreateMenu(HackingSelected)) != INVALID_HANDLE)
205 {
206 SetMenuPagination(HackingMenuHandle, 8);
207 SetMenuExitBackButton(HackingMenuHandle, true);
208 }
209
210 g_FlagLetters = CreateFlagLetters();
211
212 BuildPath(Path_SM, logFile, sizeof(logFile), "logs/sourcebans.log");
213 g_bConnecting = true;
214
215 // Catch config error and show link to FAQ
216 if (!SQL_CheckConfig("sourcebans"))
217 {
218 if (ReasonMenuHandle != INVALID_HANDLE)
219 CloseHandle(ReasonMenuHandle);
220 if (HackingMenuHandle != INVALID_HANDLE)
221 CloseHandle(HackingMenuHandle);
222 LogToFile(logFile, "Database failure: Could not find Database conf \"sourcebans\". See FAQ: https://sbpp.sarabveer.me/faq/");
223 SetFailState("Database failure: Could not find Database conf \"sourcebans\"");
224 return;
225 }
226 SQL_TConnect(GotDatabase, "sourcebans");
227
228 BuildPath(Path_SM, groupsLoc, sizeof(groupsLoc), "configs/sourcebans/sb_admin_groups.cfg");
229
230 BuildPath(Path_SM, adminsLoc, sizeof(adminsLoc), "configs/sourcebans/sb_admins.cfg");
231
232 BuildPath(Path_SM, overridesLoc, sizeof(overridesLoc), "configs/sourcebans/overrides_backup.cfg");
233
234 InitializeBackupDB();
235
236 // This timer is what processes the SQLite queue when the database is unavailable
237 CreateTimer(float(ProcessQueueTime * 60), ProcessQueue);
238
239 if (LateLoaded)
240 {
241 AccountForLateLoading();
242 }
243
244 #if defined _updater_included
245 if (LibraryExists("updater"))
246 {
247 Updater_AddPlugin(UPDATE_URL);
248 }
249 #endif
250}
251
252#if defined _updater_included
253public OnLibraryAdded(const String:name[])
254{
255 if (StrEqual(name, "updater"))
256 {
257 Updater_AddPlugin(UPDATE_URL);
258 }
259}
260#endif
261
262public OnAllPluginsLoaded()
263{
264 new Handle:topmenu;
265 #if defined DEBUG
266 LogToFile(logFile, "OnAllPluginsLoaded()");
267 #endif
268
269 if (LibraryExists("adminmenu") && ((topmenu = GetAdminTopMenu()) != INVALID_HANDLE))
270 {
271 OnAdminMenuReady(topmenu);
272 }
273}
274
275public OnConfigsExecuted()
276{
277 decl String:filename[200];
278 BuildPath(Path_SM, filename, sizeof(filename), "plugins/basebans.smx");
279 if (FileExists(filename))
280 {
281 decl String:newfilename[200];
282 BuildPath(Path_SM, newfilename, sizeof(newfilename), "plugins/disabled/basebans.smx");
283 ServerCommand("sm plugins unload basebans");
284 if (FileExists(newfilename))
285 DeleteFile(newfilename);
286 RenameFile(newfilename, filename);
287 LogToFile(logFile, "plugins/basebans.smx was unloaded and moved to plugins/disabled/basebans.smx");
288 }
289}
290
291public OnMapStart()
292{
293 ResetSettings();
294}
295
296public OnMapEnd()
297{
298 for (new i = 0; i <= MaxClients; i++)
299 {
300 if (PlayerDataPack[i] != INVALID_HANDLE)
301 {
302 /* Need to close reason pack */
303 CloseHandle(PlayerDataPack[i]);
304 PlayerDataPack[i] = INVALID_HANDLE;
305 }
306 }
307}
308
309// CLIENT CONNECTION FUNCTIONS //
310
311public Action:OnClientPreAdminCheck(client)
312{
313 if (!DB || GetUserAdmin(client) != INVALID_ADMIN_ID)
314 return Plugin_Continue;
315
316 return curLoading > 0 ? Plugin_Handled : Plugin_Continue;
317}
318
319public OnClientDisconnect(client)
320{
321 if (PlayerRecheck[client] != INVALID_HANDLE)
322 {
323 KillTimer(PlayerRecheck[client]);
324 PlayerRecheck[client] = INVALID_HANDLE;
325 }
326 g_ownReasons[client] = false;
327}
328
329public bool:OnClientConnect(client, String:rejectmsg[], maxlen)
330{
331 PlayerStatus[client] = false;
332 return true;
333}
334
335public OnClientAuthorized(client, const String:auth[])
336{
337 /* Do not check bots nor check player with lan steamid. */
338 if (auth[0] == 'B' || auth[9] == 'L' || DB == INVALID_HANDLE)
339 {
340 PlayerStatus[client] = true;
341 return;
342 }
343
344 decl String:Query[256], String:ip[30];
345 GetClientIP(client, ip, sizeof(ip));
346 FormatEx(Query, sizeof(Query), "SELECT bid FROM %s_bans WHERE ((type = 0 AND authid REGEXP '^STEAM_[0-9]:%s$') OR (type = 1 AND ip = '%s')) AND (length = '0' OR ends > UNIX_TIMESTAMP()) AND RemoveType IS NULL", DatabasePrefix, auth[8], ip);
347 #if defined DEBUG
348 LogToFile(logFile, "Checking ban for: %s", auth);
349 #endif
350
351 SQL_TQuery(DB, VerifyBan, Query, GetClientUserId(client), DBPrio_High);
352}
353
354public OnRebuildAdminCache(AdminCachePart:part)
355{
356 loadPart = part;
357 switch (loadPart)
358 {
359 case AdminCache_Overrides:
360 loadOverrides = true;
361 case AdminCache_Groups:
362 loadGroups = true;
363 case AdminCache_Admins:
364 loadAdmins = true;
365 }
366 if (DB == INVALID_HANDLE) {
367 if (!g_bConnecting) {
368 g_bConnecting = true;
369 SQL_TConnect(GotDatabase, "sourcebans");
370 }
371 }
372 else {
373 GotDatabase(DB, DB, "", 0);
374 }
375}
376
377// COMMAND CODE //
378
379public Action:ChatHook(client, args)
380{
381 // is this player preparing to ban someone
382 if (g_ownReasons[client])
383 {
384 // get the reason
385 new String:reason[512];
386 GetCmdArgString(reason, sizeof(reason));
387 StripQuotes(reason);
388
389 g_ownReasons[client] = false;
390
391 if (StrEqual(reason[0], "!noreason"))
392 {
393 PrintToChat(client, "%c[%cSourceBans%c]%c %t", GREEN, NAMECOLOR, GREEN, NAMECOLOR, "Chat Reason Aborted");
394 return Plugin_Handled;
395 }
396
397 // ban him!
398 PrepareBan(client, g_BanTarget[client], g_BanTime[client], reason, sizeof(reason));
399
400 // block the reason to be sent in chat
401 return Plugin_Handled;
402 }
403 return Plugin_Continue;
404}
405
406public Action:_CmdReload(client, args)
407{
408 ResetSettings();
409 return Plugin_Handled;
410}
411
412public Action:CommandBan(client, args)
413{
414 if (args < 2)
415 {
416 ReplyToCommand(client, "%sUsage: sm_ban <#userid|name> <time|0> [reason]", Prefix);
417 return Plugin_Handled;
418 }
419
420 // This is mainly for me sanity since client used to be called admin and target used to be called client
421 new admin = client;
422
423 // Get the target, find target returns a message on failure so we do not
424 decl String:buffer[100];
425 GetCmdArg(1, buffer, sizeof(buffer));
426 new target = FindTarget(client, buffer, true);
427 if (target == -1)
428 {
429 return Plugin_Handled;
430 }
431
432 // Get the ban time
433 GetCmdArg(2, buffer, sizeof(buffer));
434 new time = StringToInt(buffer);
435 if (!time && client && !(CheckCommandAccess(client, "sm_unban", ADMFLAG_UNBAN | ADMFLAG_ROOT)))
436 {
437 ReplyToCommand(client, "You do not have Perm Ban Permission");
438 return Plugin_Handled;
439 }
440
441 // Get the reason
442 new String:reason[128];
443 if (args >= 3)
444 {
445 GetCmdArg(3, reason, sizeof(reason));
446 for (new i = 4; i <= args; i++)
447 {
448 GetCmdArg(i, buffer, sizeof(buffer));
449 Format(reason, sizeof(reason), "%s %s", reason, buffer);
450 }
451 }
452 else
453 {
454 reason[0] = '\0';
455 }
456
457 g_BanTarget[client] = target;
458 g_BanTime[client] = time;
459
460 if (!PlayerStatus[target])
461 {
462 // The target has not been banned verify. It must be completed before you can ban anyone.
463 ReplyToCommand(admin, "%c[%cSourceBans%c]%c %t", GREEN, NAMECOLOR, GREEN, NAMECOLOR, "Ban Not Verified");
464 return Plugin_Handled;
465 }
466
467
468 CreateBan(client, target, time, reason);
469 return Plugin_Handled;
470}
471
472public Action:CommandBanIp(client, args)
473{
474 if (args < 2)
475 {
476 ReplyToCommand(client, "%sUsage: sm_banip <ip|#userid|name> <time> [reason]", Prefix);
477 return Plugin_Handled;
478 }
479
480 decl len, next_len;
481 decl String:Arguments[256];
482 decl String:arg[50], String:time[20];
483
484 GetCmdArgString(Arguments, sizeof(Arguments));
485 len = BreakString(Arguments, arg, sizeof(arg));
486
487 if ((next_len = BreakString(Arguments[len], time, sizeof(time))) != -1)
488 {
489 len += next_len;
490 }
491 else
492 {
493 len = 0;
494 Arguments[0] = '\0';
495 }
496
497 decl String:target_name[MAX_TARGET_LENGTH];
498 decl target_list[1], bool:tn_is_ml;
499 new target = -1;
500
501 if (ProcessTargetString(
502 arg,
503 client,
504 target_list,
505 1,
506 COMMAND_FILTER_CONNECTED | COMMAND_FILTER_NO_MULTI,
507 target_name,
508 sizeof(target_name),
509 tn_is_ml) > 0)
510 {
511 target = target_list[0];
512
513 if (!IsFakeClient(target) && CanUserTarget(client, target))
514 GetClientIP(target, arg, sizeof(arg));
515 }
516
517 decl String:adminIp[24], String:adminAuth[64];
518 new minutes = StringToInt(time);
519 if (!minutes && client && !(CheckCommandAccess(client, "sm_unban", ADMFLAG_UNBAN | ADMFLAG_ROOT)))
520 {
521 ReplyToCommand(client, "You do not have Perm Ban Permission");
522 return Plugin_Handled;
523 }
524 if (!client)
525 {
526 // setup dummy adminAuth and adminIp for server
527 strcopy(adminAuth, sizeof(adminAuth), "STEAM_ID_SERVER");
528 strcopy(adminIp, sizeof(adminIp), ServerIp);
529 } else {
530 GetClientIP(client, adminIp, sizeof(adminIp));
531 GetClientAuthId(client, AuthId_Steam2, adminAuth, sizeof(adminAuth));
532 }
533
534 // Pack everything into a data pack so we can retain it
535 new Handle:dataPack = CreateDataPack();
536 WritePackCell(dataPack, client);
537 WritePackCell(dataPack, minutes);
538 WritePackString(dataPack, Arguments[len]);
539 WritePackString(dataPack, arg);
540 WritePackString(dataPack, adminAuth);
541 WritePackString(dataPack, adminIp);
542
543 decl String:Query[256];
544 FormatEx(Query, sizeof(Query), "SELECT bid FROM %s_bans WHERE type = 1 AND ip = '%s' AND (length = 0 OR ends > UNIX_TIMESTAMP()) AND RemoveType IS NULL",
545 DatabasePrefix, arg);
546
547 SQL_TQuery(DB, SelectBanIpCallback, Query, dataPack, DBPrio_High);
548 return Plugin_Handled;
549}
550
551public Action:CommandUnban(client, args)
552{
553 if (args < 1)
554 {
555 ReplyToCommand(client, "%sUsage: sm_unban <steamid|ip> [reason]", Prefix);
556 return Plugin_Handled;
557 }
558
559 if (CommandDisable & DISABLE_UNBAN)
560 {
561 // They must go to the website to unban people
562 ReplyToCommand(client, "%s%t", Prefix, "Can Not Unban", WebsiteAddress);
563 return Plugin_Handled;
564 }
565
566 decl len, String:Arguments[256], String:arg[50], String:adminAuth[64];
567 GetCmdArgString(Arguments, sizeof(Arguments));
568
569 if ((len = BreakString(Arguments, arg, sizeof(arg))) == -1)
570 {
571 len = 0;
572 Arguments[0] = '\0';
573 }
574 if (!client)
575 {
576 // setup dummy adminAuth and adminIp for server
577 strcopy(adminAuth, sizeof(adminAuth), "STEAM_ID_SERVER");
578 } else {
579 GetClientAuthId(client, AuthId_Steam2, adminAuth, sizeof(adminAuth));
580 }
581
582 // Pack everything into a data pack so we can retain it
583 new Handle:dataPack = CreateDataPack();
584 WritePackCell(dataPack, client);
585 WritePackString(dataPack, Arguments[len]);
586 WritePackString(dataPack, arg);
587 WritePackString(dataPack, adminAuth);
588
589 decl String:query[200];
590 if (strncmp(arg, "STEAM_", 6) == 0)
591 {
592 Format(query, sizeof(query), "SELECT bid FROM %s_bans WHERE (type = 0 AND authid = '%s') AND (length = '0' OR ends > UNIX_TIMESTAMP()) AND RemoveType IS NULL", DatabasePrefix, arg);
593 } else {
594 Format(query, sizeof(query), "SELECT bid FROM %s_bans WHERE (type = 1 AND ip = '%s') AND (length = '0' OR ends > UNIX_TIMESTAMP()) AND RemoveType IS NULL", DatabasePrefix, arg);
595 }
596 SQL_TQuery(DB, SelectUnbanCallback, query, dataPack);
597 return Plugin_Handled;
598}
599
600public Action:CommandAddBan(client, args)
601{
602 if (args < 2)
603 {
604 ReplyToCommand(client, "%sUsage: sm_addban <time> <steamid> [reason]", Prefix);
605 return Plugin_Handled;
606 }
607
608 if (CommandDisable & DISABLE_ADDBAN)
609 {
610 // They must go to the website to add bans
611 ReplyToCommand(client, "%s%t", Prefix, "Can Not Add Ban", WebsiteAddress);
612 return Plugin_Handled;
613 }
614
615 decl String:arg_string[256], String:time[50], String:authid[50];
616 GetCmdArgString(arg_string, sizeof(arg_string));
617
618 new len, total_len;
619
620 /* Get time */
621 if ((len = BreakString(arg_string, time, sizeof(time))) == -1)
622 {
623 ReplyToCommand(client, "%sUsage: sm_addban <time> <steamid> [reason]", Prefix);
624 return Plugin_Handled;
625 }
626 total_len += len;
627
628 /* Get steamid */
629 if ((len = BreakString(arg_string[total_len], authid, sizeof(authid))) != -1)
630 {
631 total_len += len;
632 }
633 else
634 {
635 total_len = 0;
636 arg_string[0] = '\0';
637 }
638
639 decl String:adminIp[24], String:adminAuth[64];
640 new minutes = StringToInt(time);
641 if (!minutes && client && !(CheckCommandAccess(client, "sm_unban", ADMFLAG_UNBAN | ADMFLAG_ROOT)))
642 {
643 ReplyToCommand(client, "You do not have Perm Ban Permission");
644 return Plugin_Handled;
645 }
646 if (!client)
647 {
648 // setup dummy adminAuth and adminIp for server
649 strcopy(adminAuth, sizeof(adminAuth), "STEAM_ID_SERVER");
650 strcopy(adminIp, sizeof(adminIp), ServerIp);
651 } else {
652 GetClientIP(client, adminIp, sizeof(adminIp));
653 GetClientAuthId(client, AuthId_Steam2, adminAuth, sizeof(adminAuth));
654 }
655
656 // Pack everything into a data pack so we can retain it
657 new Handle:dataPack = CreateDataPack();
658 WritePackCell(dataPack, client);
659 WritePackCell(dataPack, minutes);
660 WritePackString(dataPack, arg_string[total_len]);
661 WritePackString(dataPack, authid);
662 WritePackString(dataPack, adminAuth);
663 WritePackString(dataPack, adminIp);
664
665 decl String:Query[256];
666 FormatEx(Query, sizeof(Query), "SELECT bid FROM %s_bans WHERE type = 0 AND authid = '%s' AND (length = 0 OR ends > UNIX_TIMESTAMP()) AND RemoveType IS NULL",
667 DatabasePrefix, authid);
668
669 SQL_TQuery(DB, SelectAddbanCallback, Query, dataPack, DBPrio_High);
670 return Plugin_Handled;
671}
672
673public Action:sm_rehash(args)
674{
675 if (enableAdmins)
676 DumpAdminCache(AdminCache_Groups, true);
677 DumpAdminCache(AdminCache_Overrides, true);
678 return Plugin_Handled;
679}
680
681
682
683// MENU CODE //
684
685public OnAdminMenuReady(Handle:topmenu)
686{
687 #if defined DEBUG
688 LogToFile(logFile, "OnAdminMenuReady()");
689 #endif
690
691 /* Block us from being called twice */
692 if (topmenu == hTopMenu)
693 {
694 return;
695 }
696
697 /* Save the Handle */
698 hTopMenu = topmenu;
699
700 /* Find the "Player Commands" category */
701 new TopMenuObject:player_commands = FindTopMenuCategory(hTopMenu, ADMINMENU_PLAYERCOMMANDS);
702
703 if (player_commands != INVALID_TOPMENUOBJECT)
704 {
705 // just to avoid "unused variable 'res'" warning
706 #if defined DEBUG
707 new TopMenuObject:res = AddToTopMenu(hTopMenu,
708 "sm_ban", // Name
709 TopMenuObject_Item, // We are a submenu
710 AdminMenu_Ban, // Handler function
711 player_commands, // We are a submenu of Player Commands
712 "sm_ban", // The command to be finally called (Override checks)
713 ADMFLAG_BAN); // What flag do we need to see the menu option
714 decl String:temp[125];
715 Format(temp, 125, "Result of AddToTopMenu: %d", res);
716 LogToFile(logFile, temp);
717 LogToFile(logFile, "Added Ban option to admin menu");
718 #else
719 AddToTopMenu(hTopMenu,
720 "sm_ban", // Name
721 TopMenuObject_Item, // We are a submenu
722 AdminMenu_Ban, // Handler function
723 player_commands, // We are a submenu of Player Commands
724 "sm_ban", // The command to be finally called (Override checks)
725 ADMFLAG_BAN); // What flag do we need to see the menu option
726 #endif
727 }
728}
729
730public AdminMenu_Ban(Handle:topmenu,
731 TopMenuAction:action, // Action being performed
732 TopMenuObject:object_id, // The object ID (if used)
733 param, // client idx of admin who chose the option (if used)
734 String:buffer[], // Output buffer (if used)
735 maxlength) // Output buffer (if used)
736{
737 /* Clear the Ownreason bool, so he is able to chat again;) */
738 g_ownReasons[param] = false;
739
740 #if defined DEBUG
741 LogToFile(logFile, "AdminMenu_Ban()");
742 #endif
743
744 switch (action)
745 {
746 // We are only being displayed, We only need to show the option name
747 case TopMenuAction_DisplayOption:
748 {
749 FormatEx(buffer, maxlength, "%T", "Ban player", param);
750
751 #if defined DEBUG
752 LogToFile(logFile, "AdminMenu_Ban() -> Formatted the Ban option text");
753 #endif
754 }
755
756 case TopMenuAction_SelectOption:
757 {
758 DisplayBanTargetMenu(param); // Someone chose to ban someone, show the list of users menu
759
760 #if defined DEBUG
761 LogToFile(logFile, "AdminMenu_Ban() -> DisplayBanTargetMenu()");
762 #endif
763 }
764 }
765}
766
767public ReasonSelected(Handle:menu, MenuAction:action, param1, param2)
768{
769 switch (action)
770 {
771 case MenuAction_Select:
772 {
773 decl String:info[128], String:key[128];
774 GetMenuItem(menu, param2, key, sizeof(key), _, info, sizeof(info));
775
776 if (StrEqual("Hacking", key))
777 {
778 DisplayMenu(HackingMenuHandle, param1, MENU_TIME_FOREVER);
779 return;
780 }
781
782 else if (StrEqual("Own Reason", key)) // admin wants to use his own reason
783 {
784 g_ownReasons[param1] = true;
785 PrintToChat(param1, "%c[%cSourceBans%c]%c %t", GREEN, NAMECOLOR, GREEN, NAMECOLOR, "Chat Reason");
786 return;
787 }
788
789 else if (g_BanTarget[param1] != -1 && g_BanTime[param1] != -1)
790 PrepareBan(param1, g_BanTarget[param1], g_BanTime[param1], info, sizeof(info));
791 }
792
793 case MenuAction_Cancel:
794 {
795 if (param2 == MenuCancel_Disconnected)
796 {
797 if (PlayerDataPack[param1] != INVALID_HANDLE)
798 {
799 CloseHandle(PlayerDataPack[param1]);
800 PlayerDataPack[param1] = INVALID_HANDLE;
801 }
802 }
803
804 else
805 {
806 DisplayBanTimeMenu(param1);
807 }
808 }
809 }
810}
811
812public HackingSelected(Handle:menu, MenuAction:action, param1, param2)
813{
814 switch (action)
815 {
816 case MenuAction_Select:
817 {
818 decl String:info[128], String:key[128];
819 GetMenuItem(menu, param2, key, sizeof(key), _, info, sizeof(info));
820
821 if (g_BanTarget[param1] != -1 && g_BanTime[param1] != -1)
822 PrepareBan(param1, g_BanTarget[param1], g_BanTime[param1], info, sizeof(info));
823 }
824
825 case MenuAction_Cancel:
826 {
827 if (param2 == MenuCancel_Disconnected)
828 {
829 new Handle:Pack = PlayerDataPack[param1];
830
831 if (Pack != INVALID_HANDLE)
832 {
833 ReadPackCell(Pack); // admin index
834 ReadPackCell(Pack); // target index
835 ReadPackCell(Pack); // admin userid
836 ReadPackCell(Pack); // target userid
837 ReadPackCell(Pack); // time
838 new Handle:ReasonPack = Handle:ReadPackCell(Pack);
839
840 if (ReasonPack != INVALID_HANDLE)
841 {
842 CloseHandle(ReasonPack);
843 }
844
845 CloseHandle(Pack);
846 PlayerDataPack[param1] = INVALID_HANDLE;
847 }
848 }
849
850 else
851 {
852 DisplayMenu(ReasonMenuHandle, param1, MENU_TIME_FOREVER);
853 }
854 }
855 }
856}
857
858public MenuHandler_BanPlayerList(Handle:menu, MenuAction:action, param1, param2)
859{
860 #if defined DEBUG
861 LogToFile(logFile, "MenuHandler_BanPlayerList()");
862 #endif
863
864 switch (action)
865 {
866 case MenuAction_End:
867 {
868 CloseHandle(menu);
869 }
870
871 case MenuAction_Cancel:
872 {
873 if (param2 == MenuCancel_ExitBack && hTopMenu != INVALID_HANDLE)
874 {
875 DisplayTopMenu(hTopMenu, param1, TopMenuPosition_LastCategory);
876 }
877 }
878
879 case MenuAction_Select:
880 {
881 decl String:info[32], String:name[32];
882 new userid, target;
883
884 GetMenuItem(menu, param2, info, sizeof(info), _, name, sizeof(name));
885 userid = StringToInt(info);
886
887 if ((target = GetClientOfUserId(userid)) == 0)
888 {
889 PrintToChat(param1, "%s%t", Prefix, "Player no longer available");
890 }
891 else if (!CanUserTarget(param1, target))
892 {
893 PrintToChat(param1, "%s%t", Prefix, "Unable to target");
894 }
895 else
896 {
897 g_BanTarget[param1] = target;
898 DisplayBanTimeMenu(param1);
899 }
900 }
901 }
902}
903
904public MenuHandler_BanTimeList(Handle:menu, MenuAction:action, param1, param2)
905{
906 #if defined DEBUG
907 LogToFile(logFile, "MenuHandler_BanTimeList()");
908 #endif
909
910 switch (action)
911 {
912 case MenuAction_Cancel:
913 {
914 if (param2 == MenuCancel_ExitBack && hTopMenu != INVALID_HANDLE)
915 {
916 DisplayTopMenu(hTopMenu, param1, TopMenuPosition_LastCategory);
917 }
918 }
919
920 case MenuAction_Select:
921 {
922 decl String:info[32];
923
924 GetMenuItem(menu, param2, info, sizeof(info));
925 g_BanTime[param1] = StringToInt(info);
926
927 //DisplayBanReasonMenu(param1);
928 DisplayMenu(ReasonMenuHandle, param1, MENU_TIME_FOREVER);
929 }
930
931 case MenuAction_DrawItem:
932 {
933 decl String:time[16];
934 GetMenuItem(menu, param2, time, sizeof(time));
935
936 return (StringToInt(time) > 0 || CheckCommandAccess(param1, "sm_unban", ADMFLAG_UNBAN | ADMFLAG_ROOT)) ? ITEMDRAW_DEFAULT : ITEMDRAW_DISABLED;
937 }
938 }
939
940 return 0;
941}
942
943stock DisplayBanTargetMenu(client)
944{
945 #if defined DEBUG
946 LogToFile(logFile, "DisplayBanTargetMenu()");
947 #endif
948 new Handle:menu = CreateMenu(MenuHandler_BanPlayerList); // Create a new menu, pass it the handler.
949
950 decl String:title[100];
951 FormatEx(title, sizeof(title), "%T:", "Ban player", client);
952
953 SetMenuTitle(menu, title); // Set the title
954 SetMenuExitBackButton(menu, true); // Yes we want back/exit
955
956 AddTargetsToMenu(menu, // Add clients to our menu
957 client, // The client that called the display
958 false, // We want to see people connecting
959 false); // And dead people
960
961 DisplayMenu(menu, client, MENU_TIME_FOREVER); // Show the menu to the client FOREVER!
962}
963
964stock DisplayBanTimeMenu(client)
965{
966 #if defined DEBUG
967 LogToFile(logFile, "DisplayBanTimeMenu()");
968 #endif
969
970 decl String:title[100];
971 FormatEx(title, sizeof(title), "%T:", "Ban player", client);
972 SetMenuTitle(TimeMenuHandle, title);
973
974 DisplayMenu(TimeMenuHandle, client, MENU_TIME_FOREVER);
975}
976
977stock ResetMenu()
978{
979 if (TimeMenuHandle != INVALID_HANDLE)
980 {
981 RemoveAllMenuItems(TimeMenuHandle);
982 }
983
984 if (ReasonMenuHandle != INVALID_HANDLE)
985 {
986 RemoveAllMenuItems(ReasonMenuHandle);
987 }
988
989 if (HackingMenuHandle != INVALID_HANDLE)
990 {
991 RemoveAllMenuItems(HackingMenuHandle);
992 }
993}
994
995// QUERY CALL BACKS //
996
997public GotDatabase(Handle:owner, Handle:hndl, const String:error[], any:data)
998{
999 if (hndl == INVALID_HANDLE)
1000 {
1001 LogToFile(logFile, "Database failure: %s. See FAQ: https://sbpp.sarabveer.me/faq/", error);
1002 g_bConnecting = false;
1003
1004 // Parse the overrides backup!
1005 ParseBackupConfig_Overrides();
1006 return;
1007 }
1008
1009 DB = hndl;
1010
1011 decl String:query[1024];
1012 SQL_SetCharset(DB, "utf8");
1013
1014 InsertServerInfo();
1015
1016 //CreateTimer(900.0, PruneBans);
1017
1018 if (loadOverrides)
1019 {
1020 Format(query, 1024, "SELECT type, name, flags FROM %s_overrides", DatabasePrefix);
1021 SQL_TQuery(DB, OverridesDone, query);
1022 loadOverrides = false;
1023 }
1024
1025 if (loadGroups && enableAdmins)
1026 {
1027 FormatEx(query, 1024, "SELECT name, flags, immunity, groups_immune \
1028 FROM %s_srvgroups ORDER BY id", DatabasePrefix);
1029 curLoading++;
1030 SQL_TQuery(DB, GroupsDone, query);
1031
1032 #if defined DEBUG
1033 LogToFile(logFile, "Fetching Group List");
1034 #endif
1035 loadGroups = false;
1036 }
1037
1038 if (loadAdmins && enableAdmins)
1039 {
1040 new String:queryLastLogin[50] = "";
1041
1042 if (requireSiteLogin)
1043 queryLastLogin = "lastvisit IS NOT NULL AND lastvisit != '' AND";
1044
1045 if (serverID == -1)
1046 {
1047 FormatEx(query, 1024, "SELECT authid, srv_password, (SELECT name FROM %s_srvgroups WHERE name = srv_group AND flags != '') AS srv_group, srv_flags, user, immunity \
1048 FROM %s_admins_servers_groups AS asg \
1049 LEFT JOIN %s_admins AS a ON a.aid = asg.admin_id \
1050 WHERE %s (server_id = (SELECT sid FROM %s_servers WHERE ip = '%s' AND port = '%s' LIMIT 0,1) \
1051 OR srv_group_id = ANY (SELECT group_id FROM %s_servers_groups WHERE server_id = (SELECT sid FROM %s_servers WHERE ip = '%s' AND port = '%s' LIMIT 0,1))) \
1052 GROUP BY aid, authid, srv_password, srv_group, srv_flags, user",
1053 DatabasePrefix, DatabasePrefix, DatabasePrefix, queryLastLogin, DatabasePrefix, ServerIp, ServerPort, DatabasePrefix, DatabasePrefix, ServerIp, ServerPort);
1054 } else {
1055 FormatEx(query, 1024, "SELECT authid, srv_password, (SELECT name FROM %s_srvgroups WHERE name = srv_group AND flags != '') AS srv_group, srv_flags, user, immunity \
1056 FROM %s_admins_servers_groups AS asg \
1057 LEFT JOIN %s_admins AS a ON a.aid = asg.admin_id \
1058 WHERE %s server_id = %d \
1059 OR srv_group_id = ANY (SELECT group_id FROM %s_servers_groups WHERE server_id = %d) \
1060 GROUP BY aid, authid, srv_password, srv_group, srv_flags, user",
1061 DatabasePrefix, DatabasePrefix, DatabasePrefix, queryLastLogin, serverID, DatabasePrefix, serverID);
1062 }
1063 curLoading++;
1064 SQL_TQuery(DB, AdminsDone, query);
1065
1066 #if defined DEBUG
1067 LogToFile(logFile, "Fetching Admin List");
1068 LogToFile(logFile, query);
1069 #endif
1070 loadAdmins = false;
1071 }
1072 g_bConnecting = false;
1073}
1074
1075public VerifyInsert(Handle:owner, Handle:hndl, const String:error[], any:dataPack)
1076{
1077 if (dataPack == INVALID_HANDLE)
1078 {
1079 LogToFile(logFile, "Ban Failed: %s", error);
1080 return;
1081 }
1082
1083 if (hndl == INVALID_HANDLE || error[0])
1084 {
1085 LogToFile(logFile, "Verify Insert Query Failed: %s", error);
1086 new admin = ReadPackCell(dataPack);
1087 ReadPackCell(dataPack); // target
1088 ReadPackCell(dataPack); // admin userid
1089 ReadPackCell(dataPack); // target userid
1090 new time = ReadPackCell(dataPack);
1091 new Handle:reasonPack = Handle:ReadPackCell(dataPack);
1092 new String:reason[128];
1093 ReadPackString(reasonPack, reason, sizeof(reason));
1094 decl String:name[50];
1095 ReadPackString(dataPack, name, sizeof(name));
1096 decl String:auth[30];
1097 ReadPackString(dataPack, auth, sizeof(auth));
1098 decl String:ip[20];
1099 ReadPackString(dataPack, ip, sizeof(ip));
1100 decl String:adminAuth[30];
1101 ReadPackString(dataPack, adminAuth, sizeof(adminAuth));
1102 decl String:adminIp[20];
1103 ReadPackString(dataPack, adminIp, sizeof(adminIp));
1104 ResetPack(dataPack);
1105 ResetPack(reasonPack);
1106
1107 PlayerDataPack[admin] = INVALID_HANDLE;
1108 UTIL_InsertTempBan(time, name, auth, ip, reason, adminAuth, adminIp, Handle:dataPack);
1109 return;
1110 }
1111
1112 new admin = ReadPackCell(dataPack);
1113 new client = ReadPackCell(dataPack);
1114
1115 if (!IsClientConnected(client) || IsFakeClient(client))
1116 return;
1117
1118 ReadPackCell(dataPack); // admin userid
1119 new UserId = ReadPackCell(dataPack);
1120 new time = ReadPackCell(dataPack);
1121 new Handle:ReasonPack = Handle:ReadPackCell(dataPack);
1122
1123 decl String:Name[64];
1124 new String:Reason[128];
1125
1126 ReadPackString(dataPack, Name, sizeof(Name));
1127 ReadPackString(ReasonPack, Reason, sizeof(Reason));
1128
1129 if (!time)
1130 {
1131 if (Reason[0] == '\0')
1132 {
1133 ShowActivityEx(admin, Prefix, "%t", "Permabanned player", Name);
1134 } else {
1135 ShowActivityEx(admin, Prefix, "%t", "Permabanned player reason", Name, Reason);
1136 }
1137 } else {
1138 if (Reason[0] == '\0')
1139 {
1140 ShowActivityEx(admin, Prefix, "%t", "Banned player", Name, time);
1141 } else {
1142 ShowActivityEx(admin, Prefix, "%t", "Banned player reason", Name, time, Reason);
1143 }
1144 }
1145
1146 LogAction(admin, client, "\"%L\" banned \"%L\" (minutes \"%d\") (reason \"%s\")", admin, client, time, Reason);
1147
1148 if (PlayerDataPack[admin] != INVALID_HANDLE)
1149 {
1150 CloseHandle(PlayerDataPack[admin]);
1151 CloseHandle(ReasonPack);
1152 PlayerDataPack[admin] = INVALID_HANDLE;
1153 }
1154
1155 //start nev info bans
1156
1157 char buffer[256];
1158 Format(buffer, sizeof(buffer), "SELECT * FROM %s_bans WHERE (ends > UNIX_TIMESTAMP())", DatabasePrefix);
1159 FormatTime(buffer, sizeof(buffer), "%d-%m-%Y %H:%M", (GetTime() + g_BanTime[client] + time * 60));
1160
1161 // Kick player
1162 if (GetClientUserId(client) == UserId)
1163 KickClient(client, "<font color='#ffb426'>%s</font> - Zostałeś Zbanowany! \nPowód Bana: %s \nKoniec Bana: %s <font color='99CCFF'> \nOdwołania składamy na forum!</font>", WebsiteAddress, Reason, buffer);
1164}
1165
1166public BanEnd()
1167{
1168 decl String:Query[256];
1169 FormatEx(Query, sizeof(Query), "SELECT bid FROM %s_bans WHERE (length = '0' OR ends > UNIX_TIMESTAMP())", DatabasePrefix);
1170}
1171 //end nev info bans
1172
1173public SelectBanIpCallback(Handle:owner, Handle:hndl, const String:error[], any:data)
1174{
1175 decl admin, minutes, String:adminAuth[30], String:adminIp[30], String:banReason[256], String:ip[16], String:Query[512];
1176 new String:reason[128];
1177 ResetPack(data);
1178 admin = ReadPackCell(data);
1179 minutes = ReadPackCell(data);
1180 ReadPackString(data, reason, sizeof(reason));
1181 ReadPackString(data, ip, sizeof(ip));
1182 ReadPackString(data, adminAuth, sizeof(adminAuth));
1183 ReadPackString(data, adminIp, sizeof(adminIp));
1184 SQL_EscapeString(DB, reason, banReason, sizeof(banReason));
1185
1186 if (error[0])
1187 {
1188 LogToFile(logFile, "Ban IP Select Query Failed: %s", error);
1189 if (admin && IsClientInGame(admin))
1190 PrintToChat(admin, "%sFailed to ban %s.", Prefix, ip);
1191 else
1192 PrintToServer("%sFailed to ban %s.", Prefix, ip);
1193 return;
1194 }
1195 if (SQL_GetRowCount(hndl))
1196 {
1197 if (admin && IsClientInGame(admin))
1198 PrintToChat(admin, "%s%s is already banned.", Prefix, ip);
1199 else
1200 PrintToServer("%s%s is already banned.", Prefix, ip);
1201 return;
1202 }
1203 if (serverID == -1)
1204 {
1205 FormatEx(Query, sizeof(Query), "INSERT INTO %s_bans (type, ip, name, created, ends, length, reason, aid, adminIp, sid, country) VALUES \
1206 (1, '%s', '', UNIX_TIMESTAMP(), UNIX_TIMESTAMP() + %d, %d, '%s', (SELECT aid FROM %s_admins WHERE authid = '%s' OR authid REGEXP '^STEAM_[0-9]:%s$'), '%s', \
1207 (SELECT sid FROM %s_servers WHERE ip = '%s' AND port = '%s' LIMIT 0,1), ' ')",
1208 DatabasePrefix, ip, (minutes * 60), (minutes * 60), banReason, DatabasePrefix, adminAuth, adminAuth[8], adminIp, DatabasePrefix, ServerIp, ServerPort);
1209 } else {
1210 FormatEx(Query, sizeof(Query), "INSERT INTO %s_bans (type, ip, name, created, ends, length, reason, aid, adminIp, sid, country) VALUES \
1211 (1, '%s', '', UNIX_TIMESTAMP(), UNIX_TIMESTAMP() + %d, %d, '%s', (SELECT aid FROM %s_admins WHERE authid = '%s' OR authid REGEXP '^STEAM_[0-9]:%s$'), '%s', \
1212 %d, ' ')",
1213 DatabasePrefix, ip, (minutes * 60), (minutes * 60), banReason, DatabasePrefix, adminAuth, adminAuth[8], adminIp, serverID);
1214 }
1215
1216 SQL_TQuery(DB, InsertBanIpCallback, Query, data, DBPrio_High);
1217}
1218
1219public InsertBanIpCallback(Handle:owner, Handle:hndl, const String:error[], any:data)
1220{
1221 // if the pack is good unpack it and close the handle
1222 new admin, minutes;
1223 new String:reason[128];
1224 decl String:arg[30];
1225 if (data != INVALID_HANDLE)
1226 {
1227 ResetPack(data);
1228 admin = ReadPackCell(data);
1229 minutes = ReadPackCell(data);
1230 ReadPackString(data, reason, sizeof(reason));
1231 ReadPackString(data, arg, sizeof(arg));
1232 CloseHandle(data);
1233 } else {
1234 // Technically this should not be possible
1235 ThrowError("Invalid Handle in InsertBanIpCallback");
1236 }
1237
1238 // If error is not an empty string the query failed
1239 if (error[0] != '\0')
1240 {
1241 LogToFile(logFile, "Ban IP Insert Query Failed: %s", error);
1242 if (admin && IsClientInGame(admin))
1243 PrintToChat(admin, "%ssm_banip failed", Prefix);
1244 return;
1245 }
1246
1247 LogAction(admin,
1248 -1,
1249 "\"%L\" added ban (minutes \"%d\") (ip \"%s\") (reason \"%s\")",
1250 admin,
1251 minutes,
1252 arg,
1253 reason);
1254 if (admin && IsClientInGame(admin))
1255 PrintToChat(admin, "%s%s successfully banned", Prefix, arg);
1256 else
1257 PrintToServer("%s%s successfully banned", Prefix, arg);
1258}
1259
1260public SelectUnbanCallback(Handle:owner, Handle:hndl, const String:error[], any:data)
1261{
1262 decl admin, String:arg[30], String:adminAuth[30], String:unbanReason[256];
1263 new String:reason[128];
1264 ResetPack(data);
1265 admin = ReadPackCell(data);
1266 ReadPackString(data, reason, sizeof(reason));
1267 ReadPackString(data, arg, sizeof(arg));
1268 ReadPackString(data, adminAuth, sizeof(adminAuth));
1269 SQL_EscapeString(DB, reason, unbanReason, sizeof(unbanReason));
1270
1271 // If error is not an empty string the query failed
1272 if (error[0] != '\0')
1273 {
1274 LogToFile(logFile, "Unban Select Query Failed: %s", error);
1275 if (admin && IsClientInGame(admin))
1276 {
1277 PrintToChat(admin, "%ssm_unban failed", Prefix);
1278 }
1279 return;
1280 }
1281
1282 // If there was no results then a ban does not exist for that id
1283 if (hndl == INVALID_HANDLE || !SQL_GetRowCount(hndl))
1284 {
1285 if (admin && IsClientInGame(admin))
1286 {
1287 PrintToChat(admin, "%sNo active bans found for that filter", Prefix);
1288 } else {
1289 PrintToServer("%sNo active bans found for that filter", Prefix);
1290 }
1291 return;
1292 }
1293
1294 // There is ban
1295 if (hndl != INVALID_HANDLE && SQL_FetchRow(hndl))
1296 {
1297 // Get the values from the existing ban record
1298 new bid = SQL_FetchInt(hndl, 0);
1299
1300 decl String:query[1000];
1301 Format(query, sizeof(query), "UPDATE %s_bans SET RemovedBy = (SELECT aid FROM %s_admins WHERE authid = '%s' OR authid REGEXP '^STEAM_[0-9]:%s$'), RemoveType = 'U', RemovedOn = UNIX_TIMESTAMP(), ureason = '%s' WHERE bid = %d",
1302 DatabasePrefix, DatabasePrefix, adminAuth, adminAuth[8], unbanReason, bid);
1303
1304 SQL_TQuery(DB, InsertUnbanCallback, query, data);
1305 }
1306 return;
1307}
1308
1309public InsertUnbanCallback(Handle:owner, Handle:hndl, const String:error[], any:data)
1310{
1311 // if the pack is good unpack it and close the handle
1312 decl admin, String:arg[30];
1313 new String:reason[128];
1314 if (data != INVALID_HANDLE)
1315 {
1316 ResetPack(data);
1317 admin = ReadPackCell(data);
1318 ReadPackString(data, reason, sizeof(reason));
1319 ReadPackString(data, arg, sizeof(arg));
1320 CloseHandle(data);
1321 } else {
1322 // Technically this should not be possible
1323 ThrowError("Invalid Handle in InsertUnbanCallback");
1324 }
1325
1326 // If error is not an empty string the query failed
1327 if (error[0] != '\0')
1328 {
1329 LogToFile(logFile, "Unban Insert Query Failed: %s", error);
1330 if (admin && IsClientInGame(admin))
1331 {
1332 PrintToChat(admin, "%ssm_unban failed", Prefix);
1333 }
1334 return;
1335 }
1336
1337 LogAction(admin, -1, "\"%L\" removed ban (filter \"%s\") (reason \"%s\")", admin, arg, reason);
1338 if (admin && IsClientInGame(admin))
1339 {
1340 PrintToChat(admin, "%s%s successfully unbanned", Prefix, arg);
1341 } else {
1342 PrintToServer("%s%s successfully unbanned", Prefix, arg);
1343 }
1344}
1345
1346public SelectAddbanCallback(Handle:owner, Handle:hndl, const String:error[], any:data)
1347{
1348 decl admin, minutes, String:adminAuth[30], String:adminIp[30], String:authid[20], String:banReason[256], String:Query[512];
1349 new String:reason[128];
1350 ResetPack(data);
1351 admin = ReadPackCell(data);
1352 minutes = ReadPackCell(data);
1353 ReadPackString(data, reason, sizeof(reason));
1354 ReadPackString(data, authid, sizeof(authid));
1355 ReadPackString(data, adminAuth, sizeof(adminAuth));
1356 ReadPackString(data, adminIp, sizeof(adminIp));
1357 SQL_EscapeString(DB, reason, banReason, sizeof(banReason));
1358
1359 if (error[0])
1360 {
1361 LogToFile(logFile, "Add Ban Select Query Failed: %s", error);
1362 if (admin && IsClientInGame(admin))
1363 PrintToChat(admin, "%sFailed to ban %s.", Prefix, authid);
1364 else
1365 PrintToServer("%sFailed to ban %s.", Prefix, authid);
1366 return;
1367 }
1368 if (SQL_GetRowCount(hndl))
1369 {
1370 if (admin && IsClientInGame(admin))
1371 PrintToChat(admin, "%s%s is already banned.", Prefix, authid);
1372 else
1373 PrintToServer("%s%s is already banned.", Prefix, authid);
1374 return;
1375 }
1376 if (serverID == -1)
1377 {
1378 FormatEx(Query, sizeof(Query), "INSERT INTO %s_bans (authid, name, created, ends, length, reason, aid, adminIp, sid, country) VALUES \
1379 ('%s', '', UNIX_TIMESTAMP(), UNIX_TIMESTAMP() + %d, %d, '%s', (SELECT aid FROM %s_admins WHERE authid = '%s' OR authid REGEXP '^STEAM_[0-9]:%s$'), '%s', \
1380 (SELECT sid FROM %s_servers WHERE ip = '%s' AND port = '%s' LIMIT 0,1), ' ')",
1381 DatabasePrefix, authid, (minutes * 60), (minutes * 60), banReason, DatabasePrefix, adminAuth, adminAuth[8], adminIp, DatabasePrefix, ServerIp, ServerPort);
1382 } else {
1383 FormatEx(Query, sizeof(Query), "INSERT INTO %s_bans (authid, name, created, ends, length, reason, aid, adminIp, sid, country) VALUES \
1384 ('%s', '', UNIX_TIMESTAMP(), UNIX_TIMESTAMP() + %d, %d, '%s', (SELECT aid FROM %s_admins WHERE authid = '%s' OR authid REGEXP '^STEAM_[0-9]:%s$'), '%s', \
1385 %d, ' ')",
1386 DatabasePrefix, authid, (minutes * 60), (minutes * 60), banReason, DatabasePrefix, adminAuth, adminAuth[8], adminIp, serverID);
1387 }
1388
1389 SQL_TQuery(DB, InsertAddbanCallback, Query, data, DBPrio_High);
1390}
1391
1392public InsertAddbanCallback(Handle:owner, Handle:hndl, const String:error[], any:data)
1393{
1394 decl admin, minutes, String:authid[20];
1395 new String:reason[128];
1396 ResetPack(data);
1397 admin = ReadPackCell(data);
1398 minutes = ReadPackCell(data);
1399 ReadPackString(data, reason, sizeof(reason));
1400 ReadPackString(data, authid, sizeof(authid));
1401
1402 // If error is not an empty string the query failed
1403 if (error[0] != '\0')
1404 {
1405 LogToFile(logFile, "Add Ban Insert Query Failed: %s", error);
1406 if (admin && IsClientInGame(admin))
1407 {
1408 PrintToChat(admin, "%ssm_addban failed", Prefix);
1409 }
1410 return;
1411 }
1412
1413 LogAction(admin,
1414 -1,
1415 "\"%L\" added ban (minutes \"%i\") (id \"%s\") (reason \"%s\")",
1416 admin,
1417 minutes,
1418 authid,
1419 reason);
1420 if (admin && IsClientInGame(admin))
1421 {
1422 PrintToChat(admin, "%s%s successfully banned", Prefix, authid);
1423 } else {
1424 PrintToServer("%s%s successfully banned", Prefix, authid);
1425 }
1426}
1427
1428// ProcessQueueCallback is called as the result of selecting all the rows from the queue table
1429public ProcessQueueCallback(Handle:owner, Handle:hndl, const String:error[], any:data)
1430{
1431 if (hndl == INVALID_HANDLE || strlen(error) > 0)
1432 {
1433 LogToFile(logFile, "Failed to retrieve queued bans from sqlite database, %s", error);
1434 return;
1435 }
1436
1437 decl String:auth[30];
1438 decl time;
1439 decl startTime;
1440 new String:reason[128];
1441 decl String:name[64];
1442 decl String:ip[20];
1443 decl String:adminAuth[30];
1444 decl String:adminIp[20];
1445 decl String:query[1024];
1446 decl String:banName[128];
1447 decl String:banReason[256];
1448 while (SQL_MoreRows(hndl))
1449 {
1450 // Oh noes! What happened?!
1451 if (!SQL_FetchRow(hndl))
1452 continue;
1453
1454 // if we get to here then there are rows in the queue pending processing
1455 SQL_FetchString(hndl, 0, auth, sizeof(auth));
1456 time = SQL_FetchInt(hndl, 1);
1457 startTime = SQL_FetchInt(hndl, 2);
1458 SQL_FetchString(hndl, 3, reason, sizeof(reason));
1459 SQL_FetchString(hndl, 4, name, sizeof(name));
1460 SQL_FetchString(hndl, 5, ip, sizeof(ip));
1461 SQL_FetchString(hndl, 6, adminAuth, sizeof(adminAuth));
1462 SQL_FetchString(hndl, 7, adminIp, sizeof(adminIp));
1463 SQL_EscapeString(SQLiteDB, name, banName, sizeof(banName));
1464 SQL_EscapeString(SQLiteDB, reason, banReason, sizeof(banReason));
1465 if (startTime + time * 60 > GetTime() || time == 0)
1466 {
1467 // This ban is still valid and should be entered into the db
1468 if (serverID == -1)
1469 {
1470 FormatEx(query, sizeof(query),
1471 "INSERT INTO %s_bans (ip, authid, name, created, ends, length, reason, aid, adminIp, sid) VALUES \
1472 ('%s', '%s', '%s', %d, %d, %d, '%s', (SELECT aid FROM %s_admins WHERE authid = '%s' OR authid REGEXP '^STEAM_[0-9]:%s$'), '%s', \
1473 (SELECT sid FROM %s_servers WHERE ip = '%s' AND port = '%s' LIMIT 0,1))",
1474 DatabasePrefix, ip, auth, banName, startTime, startTime + time * 60, time * 60, banReason, DatabasePrefix, adminAuth, adminAuth[8], adminIp, DatabasePrefix, ServerIp, ServerPort);
1475 }
1476 else
1477 {
1478 FormatEx(query, sizeof(query),
1479 "INSERT INTO %s_bans (ip, authid, name, created, ends, length, reason, aid, adminIp, sid) VALUES \
1480 ('%s', '%s', '%s', %d, %d, %d, '%s', (SELECT aid FROM %s_admins WHERE authid = '%s' OR authid REGEXP '^STEAM_[0-9]:%s$'), '%s', \
1481 %d)",
1482 DatabasePrefix, ip, auth, banName, startTime, startTime + time * 60, time * 60, banReason, DatabasePrefix, adminAuth, adminAuth[8], adminIp, serverID);
1483 }
1484 new Handle:authPack = CreateDataPack();
1485 WritePackString(authPack, auth);
1486 ResetPack(authPack);
1487 SQL_TQuery(DB, AddedFromSQLiteCallback, query, authPack);
1488 } else {
1489 // The ban is no longer valid and should be deleted from the queue
1490 FormatEx(query, sizeof(query), "DELETE FROM queue WHERE steam_id = '%s'", auth);
1491 SQL_TQuery(SQLiteDB, ErrorCheckCallback, query);
1492 }
1493 }
1494 // We have finished processing the queue but should process again in ProcessQueueTime minutes
1495 CreateTimer(float(ProcessQueueTime * 60), ProcessQueue);
1496}
1497
1498public AddedFromSQLiteCallback(Handle:owner, Handle:hndl, const String:error[], any:data)
1499{
1500 decl String:buffer[512];
1501 decl String:auth[40];
1502 ReadPackString(data, auth, sizeof(auth));
1503 if (error[0] == '\0')
1504 {
1505 // The insert was successful so delete the record from the queue
1506 FormatEx(buffer, sizeof(buffer), "DELETE FROM queue WHERE steam_id = '%s'", auth);
1507 SQL_TQuery(SQLiteDB, ErrorCheckCallback, buffer);
1508
1509 // They are added to main banlist, so remove the temp ban
1510 RemoveBan(auth, BANFLAG_AUTHID);
1511
1512 } else {
1513 // the insert failed so we leave the record in the queue and increase our temporary ban
1514 FormatEx(buffer, sizeof(buffer), "banid %d %s", ProcessQueueTime, auth);
1515 ServerCommand(buffer);
1516 }
1517 CloseHandle(data);
1518}
1519
1520public ServerInfoCallback(Handle:owner, Handle:hndl, const String:error[], any:data)
1521{
1522 if (error[0])
1523 {
1524 LogToFile(logFile, "Server Select Query Failed: %s", error);
1525 return;
1526 }
1527
1528 if (hndl == INVALID_HANDLE || SQL_GetRowCount(hndl) == 0)
1529 {
1530 // get the game folder name used to determine the mod
1531 decl String:desc[64], String:query[200];
1532 GetGameFolderName(desc, sizeof(desc));
1533 FormatEx(query, sizeof(query), "INSERT INTO %s_servers (ip, port, rcon, modid) VALUES ('%s', '%s', '', (SELECT mid FROM %s_mods WHERE modfolder = '%s'))", DatabasePrefix, ServerIp, ServerPort, DatabasePrefix, desc);
1534 SQL_TQuery(DB, ErrorCheckCallback, query);
1535 }
1536}
1537
1538public ErrorCheckCallback(Handle:owner, Handle:hndle, const String:error[], any:data)
1539{
1540 if (error[0])
1541 {
1542 LogToFile(logFile, "Query Failed: %s", error);
1543 }
1544}
1545
1546public VerifyBan(Handle:owner, Handle:hndl, const String:error[], any:userid)
1547{
1548 decl String:clientName[64];
1549 decl String:clientAuth[64];
1550 decl String:clientIp[64];
1551 new client = GetClientOfUserId(userid);
1552
1553 if (!client)
1554 return;
1555
1556 /* Failure happen. Do retry with delay */
1557 if (hndl == INVALID_HANDLE)
1558 {
1559 LogToFile(logFile, "Verify Ban Query Failed: %s", error);
1560 PlayerRecheck[client] = CreateTimer(RetryTime, ClientRecheck, client);
1561 return;
1562 }
1563 GetClientIP(client, clientIp, sizeof(clientIp));
1564 GetClientAuthId(client, AuthId_Steam2, clientAuth, sizeof(clientAuth));
1565 GetClientName(client, clientName, sizeof(clientName));
1566 if (SQL_GetRowCount(hndl) > 0)
1567 {
1568 decl String:buffer[40];
1569 decl String:Name[128];
1570 decl String:Query[512];
1571
1572 SQL_EscapeString(DB, clientName, Name, sizeof(Name));
1573 if (serverID == -1)
1574 {
1575 FormatEx(Query, sizeof(Query), "INSERT INTO %s_banlog (sid ,time ,name ,bid) VALUES \
1576 ((SELECT sid FROM %s_servers WHERE ip = '%s' AND port = '%s' LIMIT 0,1), UNIX_TIMESTAMP(), '%s', \
1577 (SELECT bid FROM %s_bans WHERE ((type = 0 AND authid REGEXP '^STEAM_[0-9]:%s$') OR (type = 1 AND ip = '%s')) AND RemoveType IS NULL LIMIT 0,1))",
1578 DatabasePrefix, DatabasePrefix, ServerIp, ServerPort, Name, DatabasePrefix, clientAuth[8], clientIp);
1579 }
1580 else
1581 {
1582 FormatEx(Query, sizeof(Query), "INSERT INTO %s_banlog (sid ,time ,name ,bid) VALUES \
1583 (%d, UNIX_TIMESTAMP(), '%s', \
1584 (SELECT bid FROM %s_bans WHERE ((type = 0 AND authid REGEXP '^STEAM_[0-9]:%s$') OR (type = 1 AND ip = '%s')) AND RemoveType IS NULL LIMIT 0,1))",
1585 DatabasePrefix, serverID, Name, DatabasePrefix, clientAuth[8], clientIp);
1586 }
1587
1588 SQL_TQuery(DB, ErrorCheckCallback, Query, client, DBPrio_High);
1589 FormatEx(buffer, sizeof(buffer), "banid 5 %s", clientAuth);
1590 ServerCommand(buffer);
1591 KickClient(client, "%t", "Banned Check Site", WebsiteAddress);
1592 return;
1593 }
1594 #if defined DEBUG
1595 LogToFile(logFile, "%s is NOT banned.", clientAuth);
1596 #endif
1597
1598 PlayerStatus[client] = true;
1599}
1600
1601public AdminsDone(Handle:owner, Handle:hndl, const String:error[], any:data)
1602{
1603 //SELECT authid, srv_password , srv_group, srv_flags, user
1604 if (hndl == INVALID_HANDLE || strlen(error) > 0)
1605 {
1606 --curLoading;
1607 CheckLoadAdmins();
1608 LogToFile(logFile, "Failed to retrieve admins from the database, %s", error);
1609 return;
1610 }
1611 decl String:authType[] = "steam";
1612 decl String:identity[66];
1613 decl String:password[66];
1614 decl String:groups[256];
1615 decl String:flags[32];
1616 decl String:name[66];
1617 new admCount = 0;
1618 new Immunity = 0;
1619 new AdminId:curAdm = INVALID_ADMIN_ID;
1620 new Handle:adminsKV = CreateKeyValues("Admins");
1621
1622 while (SQL_MoreRows(hndl))
1623 {
1624 SQL_FetchRow(hndl);
1625 if (SQL_IsFieldNull(hndl, 0))
1626 continue; // Sometimes some rows return NULL due to some setups
1627
1628 SQL_FetchString(hndl, 0, identity, 66);
1629 SQL_FetchString(hndl, 1, password, 66);
1630 SQL_FetchString(hndl, 2, groups, 256);
1631 SQL_FetchString(hndl, 3, flags, 32);
1632 SQL_FetchString(hndl, 4, name, 66);
1633
1634 Immunity = SQL_FetchInt(hndl, 5);
1635
1636 TrimString(name);
1637 TrimString(identity);
1638 TrimString(groups);
1639 TrimString(flags);
1640
1641 // Disable writing to file if they chose to
1642 if (backupConfig)
1643 {
1644 KvJumpToKey(adminsKV, name, true);
1645
1646 KvSetString(adminsKV, "auth", authType);
1647 KvSetString(adminsKV, "identity", identity);
1648
1649 if (strlen(flags) > 0)
1650 KvSetString(adminsKV, "flags", flags);
1651
1652 if (strlen(groups) > 0)
1653 KvSetString(adminsKV, "group", groups);
1654
1655 if (strlen(password) > 0)
1656 KvSetString(adminsKV, "password", password);
1657
1658 if (Immunity > 0)
1659 KvSetNum(adminsKV, "immunity", Immunity);
1660
1661 KvRewind(adminsKV);
1662 }
1663
1664 // find or create the admin using that identity
1665 if ((curAdm = FindAdminByIdentity(authType, identity)) == INVALID_ADMIN_ID)
1666 {
1667 curAdm = CreateAdmin(name);
1668 // That should never happen!
1669 if (!BindAdminIdentity(curAdm, authType, identity))
1670 {
1671 LogToFile(logFile, "Unable to bind admin %s to identity %s", name, identity);
1672 RemoveAdmin(curAdm);
1673 continue;
1674 }
1675 }
1676
1677 #if defined DEBUG
1678 LogToFile(logFile, "Given %s (%s) admin", name, identity);
1679 #endif
1680
1681 new curPos = 0;
1682 new GroupId:curGrp = INVALID_GROUP_ID;
1683 new numGroups;
1684 decl String:iterGroupName[64];
1685
1686 // Who thought this comma seperated group parsing would be a good idea?!
1687 /*
1688 decl String:grp[64];
1689 new nextPos = 0;
1690 while ((nextPos = SplitString(groups[curPos],",",grp,64)) != -1)
1691 {
1692 curPos += nextPos;
1693 curGrp = FindAdmGroup(grp);
1694 if (curGrp == INVALID_GROUP_ID)
1695 {
1696 LogToFile(logFile, "Unknown group \"%s\"",grp);
1697 }
1698 else
1699 {
1700 // Check, if he's not in the group already.
1701 numGroups = GetAdminGroupCount(curAdm);
1702 for(new i=0;i<numGroups;i++)
1703 {
1704 GetAdminGroup(curAdm, i, iterGroupName, sizeof(iterGroupName));
1705 // Admin is already part of the group, so don't try to inherit its permissions.
1706 if(StrEqual(iterGroupName, grp))
1707 {
1708 numGroups = -2;
1709 break;
1710 }
1711 }
1712 // Only try to inherit the group, if it's a new one.
1713 if (numGroups != -2 && !AdminInheritGroup(curAdm,curGrp))
1714 {
1715 LogToFile(logFile, "Unable to inherit group \"%s\"",grp);
1716 }
1717 }
1718 }*/
1719
1720 if (strcmp(groups[curPos], "") != 0)
1721 {
1722 curGrp = FindAdmGroup(groups[curPos]);
1723 if (curGrp == INVALID_GROUP_ID)
1724 {
1725 LogToFile(logFile, "Unknown group \"%s\"", groups[curPos]);
1726 }
1727 else
1728 {
1729 // Check, if he's not in the group already.
1730 numGroups = GetAdminGroupCount(curAdm);
1731 for (new i = 0; i < numGroups; i++)
1732 {
1733 GetAdminGroup(curAdm, i, iterGroupName, sizeof(iterGroupName));
1734 // Admin is already part of the group, so don't try to inherit its permissions.
1735 if (StrEqual(iterGroupName, groups[curPos]))
1736 {
1737 numGroups = -2;
1738 break;
1739 }
1740 }
1741
1742 // Only try to inherit the group, if it's a new one.
1743 if (numGroups != -2 && !AdminInheritGroup(curAdm, curGrp))
1744 {
1745 LogToFile(logFile, "Unable to inherit group \"%s\"", groups[curPos]);
1746 }
1747
1748 if (GetAdminImmunityLevel(curAdm) < Immunity)
1749 {
1750 SetAdminImmunityLevel(curAdm, Immunity);
1751 }
1752 #if defined DEBUG
1753 LogToFile(logFile, "Admin %s (%s) has %d immunity", name, identity, Immunity);
1754 #endif
1755 }
1756 }
1757
1758 if (strlen(password) > 0)
1759 SetAdminPassword(curAdm, password);
1760
1761 for (new i = 0; i < strlen(flags); ++i)
1762 {
1763 if (flags[i] < 'a' || flags[i] > 'z')
1764 continue;
1765
1766 if (g_FlagLetters[flags[i]-'a'] < Admin_Reservation)
1767 continue;
1768
1769 SetAdminFlag(curAdm, g_FlagLetters[flags[i]-'a'], true);
1770 }
1771 ++admCount;
1772 }
1773
1774 if (backupConfig)
1775 KeyValuesToFile(adminsKV, adminsLoc);
1776 CloseHandle(adminsKV);
1777
1778 #if defined DEBUG
1779 LogToFile(logFile, "Finished loading %i admins.", admCount);
1780 #endif
1781
1782 --curLoading;
1783 CheckLoadAdmins();
1784}
1785
1786public GroupsDone(Handle:owner, Handle:hndl, const String:error[], any:data)
1787{
1788 if (hndl == INVALID_HANDLE)
1789 {
1790 curLoading--;
1791 CheckLoadAdmins();
1792 LogToFile(logFile, "Failed to retrieve groups from the database, %s", error);
1793 return;
1794 }
1795 decl String:grpName[128], String:immuneGrpName[128];
1796 decl String:grpFlags[32];
1797 new Immunity;
1798 new grpCount = 0;
1799 new Handle:groupsKV = CreateKeyValues("Groups");
1800
1801 new GroupId:curGrp = INVALID_GROUP_ID;
1802 while (SQL_MoreRows(hndl))
1803 {
1804 SQL_FetchRow(hndl);
1805 if (SQL_IsFieldNull(hndl, 0))
1806 continue; // Sometimes some rows return NULL due to some setups
1807 SQL_FetchString(hndl, 0, grpName, 128);
1808 SQL_FetchString(hndl, 1, grpFlags, 32);
1809 Immunity = SQL_FetchInt(hndl, 2);
1810 SQL_FetchString(hndl, 3, immuneGrpName, 128);
1811
1812 TrimString(grpName);
1813 TrimString(grpFlags);
1814 TrimString(immuneGrpName);
1815
1816 // Ignore empty rows..
1817 if (!strlen(grpName))
1818 continue;
1819
1820 curGrp = CreateAdmGroup(grpName);
1821
1822 if (backupConfig)
1823 {
1824 KvJumpToKey(groupsKV, grpName, true);
1825 if (strlen(grpFlags) > 0)
1826 KvSetString(groupsKV, "flags", grpFlags);
1827 if (Immunity > 0)
1828 KvSetNum(groupsKV, "immunity", Immunity);
1829
1830 KvRewind(groupsKV);
1831 }
1832
1833 if (curGrp == INVALID_GROUP_ID)
1834 { //This occurs when the group already exists
1835 curGrp = FindAdmGroup(grpName);
1836 }
1837
1838 for (new i = 0; i < strlen(grpFlags); ++i)
1839 {
1840 if (grpFlags[i] < 'a' || grpFlags[i] > 'z')
1841 continue;
1842
1843 if (g_FlagLetters[grpFlags[i]-'a'] < Admin_Reservation)
1844 continue;
1845
1846 SetAdmGroupAddFlag(curGrp, g_FlagLetters[grpFlags[i]-'a'], true);
1847 }
1848
1849 // Set the group immunity.
1850 if (Immunity > 0)
1851 {
1852 SetAdmGroupImmunityLevel(curGrp, Immunity);
1853 #if defined DEBUG
1854 LogToFile(logFile, "Group %s has %d immunity", grpName, Immunity);
1855 #endif
1856 }
1857
1858 grpCount++;
1859 }
1860
1861 if (backupConfig)
1862 KeyValuesToFile(groupsKV, groupsLoc);
1863 CloseHandle(groupsKV);
1864
1865 #if defined DEBUG
1866 LogToFile(logFile, "Finished loading %i groups.", grpCount);
1867 #endif
1868
1869 // Load the group overrides
1870 decl String:query[512];
1871 FormatEx(query, 512, "SELECT sg.name, so.type, so.name, so.access FROM %s_srvgroups_overrides so LEFT JOIN %s_srvgroups sg ON sg.id = so.group_id ORDER BY sg.id", DatabasePrefix, DatabasePrefix);
1872 SQL_TQuery(DB, LoadGroupsOverrides, query);
1873
1874 /*if (reparse)
1875 {
1876 decl String:query[512];
1877 FormatEx(query,512,"SELECT name, immunity, groups_immune FROM %s_srvgroups ORDER BY id",DatabasePrefix);
1878 SQL_TQuery(DB,GroupsSecondPass,query);
1879 }
1880 else
1881 {
1882 curLoading--;
1883 CheckLoadAdmins();
1884 }*/
1885}
1886
1887// Reparse to apply inherited immunity
1888public GroupsSecondPass(Handle:owner, Handle:hndl, const String:error[], any:data)
1889{
1890 if (hndl == INVALID_HANDLE)
1891 {
1892 curLoading--;
1893 CheckLoadAdmins();
1894 LogToFile(logFile, "Failed to retrieve groups from the database, %s", error);
1895 return;
1896 }
1897 decl String:grpName[128], String:immunityGrpName[128];
1898
1899 new GroupId:curGrp = INVALID_GROUP_ID;
1900 new GroupId:immuneGrp = INVALID_GROUP_ID;
1901 while (SQL_MoreRows(hndl))
1902 {
1903 SQL_FetchRow(hndl);
1904 if (SQL_IsFieldNull(hndl, 0))
1905 continue; // Sometimes some rows return NULL due to some setups
1906
1907 SQL_FetchString(hndl, 0, grpName, 128);
1908 TrimString(grpName);
1909 if (strlen(grpName) == 0)
1910 continue;
1911
1912 SQL_FetchString(hndl, 2, immunityGrpName, sizeof(immunityGrpName));
1913 TrimString(immunityGrpName);
1914
1915 curGrp = FindAdmGroup(grpName);
1916 if (curGrp == INVALID_GROUP_ID)
1917 continue;
1918
1919 immuneGrp = FindAdmGroup(immunityGrpName);
1920 if (immuneGrp == INVALID_GROUP_ID)
1921 continue;
1922
1923 SetAdmGroupImmuneFrom(curGrp, immuneGrp);
1924
1925 #if defined DEBUG
1926 LogToFile(logFile, "Group %s inhertied immunity from group %s", grpName, immunityGrpName);
1927 #endif
1928 }
1929 --curLoading;
1930 CheckLoadAdmins();
1931}
1932
1933public LoadGroupsOverrides(Handle:owner, Handle:hndl, const String:error[], any:data)
1934{
1935 if (hndl == INVALID_HANDLE)
1936 {
1937 curLoading--;
1938 CheckLoadAdmins();
1939 LogToFile(logFile, "Failed to retrieve group overrides from the database, %s", error);
1940 return;
1941 }
1942 decl String:sGroupName[128], String:sType[16], String:sCommand[64], String:sAllowed[16];
1943 decl OverrideRule:iRule, OverrideType:iType;
1944
1945 new Handle:groupsKV = CreateKeyValues("Groups");
1946 FileToKeyValues(groupsKV, groupsLoc);
1947
1948 new GroupId:curGrp = INVALID_GROUP_ID;
1949 while (SQL_MoreRows(hndl))
1950 {
1951 SQL_FetchRow(hndl);
1952 if (SQL_IsFieldNull(hndl, 0))
1953 continue; // Sometimes some rows return NULL due to some setups
1954
1955 SQL_FetchString(hndl, 0, sGroupName, sizeof(sGroupName));
1956 TrimString(sGroupName);
1957 if (strlen(sGroupName) == 0)
1958 continue;
1959
1960 SQL_FetchString(hndl, 1, sType, sizeof(sType));
1961 SQL_FetchString(hndl, 2, sCommand, sizeof(sCommand));
1962 SQL_FetchString(hndl, 3, sAllowed, sizeof(sAllowed));
1963
1964 curGrp = FindAdmGroup(sGroupName);
1965 if (curGrp == INVALID_GROUP_ID)
1966 continue;
1967
1968 iRule = StrEqual(sAllowed, "allow") ? Command_Allow : Command_Deny;
1969 iType = StrEqual(sType, "group") ? Override_CommandGroup : Override_Command;
1970
1971 #if defined DEBUG
1972 PrintToServer("AddAdmGroupCmdOverride(%i, %s, %i, %i)", curGrp, sCommand, iType, iRule);
1973 #endif
1974
1975 // Save overrides into admin_groups.cfg backup
1976 if (KvJumpToKey(groupsKV, sGroupName))
1977 {
1978 KvJumpToKey(groupsKV, "Overrides", true);
1979 if (iType == Override_Command)
1980 KvSetString(groupsKV, sCommand, sAllowed);
1981 else
1982 {
1983 Format(sCommand, sizeof(sCommand), "@%s", sCommand);
1984 KvSetString(groupsKV, sCommand, sAllowed);
1985 }
1986 KvRewind(groupsKV);
1987 }
1988
1989 AddAdmGroupCmdOverride(curGrp, sCommand, iType, iRule);
1990 }
1991 curLoading--;
1992 CheckLoadAdmins();
1993
1994 if (backupConfig)
1995 KeyValuesToFile(groupsKV, groupsLoc);
1996 CloseHandle(groupsKV);
1997}
1998
1999public OverridesDone(Handle:owner, Handle:hndl, const String:error[], any:data)
2000{
2001 if (hndl == INVALID_HANDLE)
2002 {
2003 LogToFile(logFile, "Failed to retrieve overrides from the database, %s", error);
2004 ParseBackupConfig_Overrides();
2005 return;
2006 }
2007
2008 new Handle:hKV = CreateKeyValues("SB_Overrides");
2009
2010 decl String:sFlags[32], String:sName[64], String:sType[64];
2011 while (SQL_FetchRow(hndl))
2012 {
2013 SQL_FetchString(hndl, 0, sType, sizeof(sType));
2014 SQL_FetchString(hndl, 1, sName, sizeof(sName));
2015 SQL_FetchString(hndl, 2, sFlags, sizeof(sFlags));
2016
2017 // KeyValuesToFile won't add that key, if the value is ""..
2018 if (sFlags[0] == '\0')
2019 {
2020 sFlags[0] = ' ';
2021 sFlags[1] = '\0';
2022 }
2023
2024 #if defined DEBUG
2025 LogToFile(logFile, "Adding override (%s, %s, %s)", sType, sName, sFlags);
2026 #endif
2027
2028 if (StrEqual(sType, "command"))
2029 {
2030 AddCommandOverride(sName, Override_Command, ReadFlagString(sFlags));
2031 KvJumpToKey(hKV, "override_commands", true);
2032 KvSetString(hKV, sName, sFlags);
2033 KvGoBack(hKV);
2034 }
2035 else if (StrEqual(sType, "group"))
2036 {
2037 AddCommandOverride(sName, Override_CommandGroup, ReadFlagString(sFlags));
2038 KvJumpToKey(hKV, "override_groups", true);
2039 KvSetString(hKV, sName, sFlags);
2040 KvGoBack(hKV);
2041 }
2042 }
2043
2044 KvRewind(hKV);
2045
2046 if (backupConfig)
2047 KeyValuesToFile(hKV, overridesLoc);
2048 CloseHandle(hKV);
2049}
2050
2051// TIMER CALL BACKS //
2052
2053public Action:ClientRecheck(Handle:timer, any:client)
2054{
2055 decl String:Authid[64];
2056 if (!PlayerStatus[client] && IsClientConnected(client) && GetClientAuthId(client, AuthId_Steam2, Authid, sizeof(Authid)))
2057 {
2058 OnClientAuthorized(client, Authid);
2059 }
2060
2061 PlayerRecheck[client] = INVALID_HANDLE;
2062 return Plugin_Stop;
2063}
2064
2065/*
2066public Action:PruneBans(Handle:timer)
2067{
2068 decl String:Query[512];
2069 FormatEx(Query, sizeof(Query),
2070 "UPDATE %s_bans SET RemovedBy = 0, RemoveType = 'E', RemovedOn = UNIX_TIMESTAMP() WHERE length != '0' AND ends < UNIX_TIMESTAMP()",
2071 DatabasePrefix);
2072
2073 SQL_TQuery(DB, ErrorCheckCallback, Query);
2074 return Plugin_Continue;
2075}
2076*/
2077
2078public Action:ProcessQueue(Handle:timer, any:data)
2079{
2080 decl String:buffer[512];
2081 Format(buffer, sizeof(buffer), "SELECT steam_id, time, start_time, reason, name, ip, admin_id, admin_ip FROM queue");
2082 SQL_TQuery(SQLiteDB, ProcessQueueCallback, buffer);
2083}
2084
2085// PARSER //
2086
2087static InitializeConfigParser()
2088{
2089 if (ConfigParser == INVALID_HANDLE)
2090 {
2091 ConfigParser = SMC_CreateParser();
2092 SMC_SetReaders(ConfigParser, ReadConfig_NewSection, ReadConfig_KeyValue, ReadConfig_EndSection);
2093 }
2094}
2095
2096static InternalReadConfig(const String:path[])
2097{
2098 ConfigState = ConfigStateNone;
2099
2100 new SMCError:err = SMC_ParseFile(ConfigParser, path);
2101
2102 if (err != SMCError_Okay)
2103 {
2104 decl String:buffer[64];
2105 PrintToServer("%s", SMC_GetErrorString(err, buffer, sizeof(buffer)) ? buffer : "Fatal parse error");
2106 }
2107}
2108
2109public SMCResult:ReadConfig_NewSection(Handle:smc, const String:name[], bool:opt_quotes)
2110{
2111 if (name[0])
2112 {
2113 if (strcmp("Config", name, false) == 0) {
2114 ConfigState = ConfigStateConfig;
2115 } else if (strcmp("BanReasons", name, false) == 0) {
2116 ConfigState = ConfigStateReasons;
2117 } else if (strcmp("HackingReasons", name, false) == 0) {
2118 ConfigState = ConfigStateHacking;
2119 } else if (strcmp("BanTime", name, false) == 0) {
2120 ConfigState = ConfigStateTime;
2121 }
2122 }
2123 return SMCParse_Continue;
2124}
2125
2126public SMCResult:ReadConfig_KeyValue(Handle:smc, const String:key[], const String:value[], bool:key_quotes, bool:value_quotes)
2127{
2128 if (!key[0])
2129 return SMCParse_Continue;
2130
2131 switch (ConfigState)
2132 {
2133 case ConfigStateConfig:
2134 {
2135 if (strcmp("website", key, false) == 0)
2136 {
2137 strcopy(WebsiteAddress, sizeof(WebsiteAddress), value);
2138 }
2139 else if (strcmp("Addban", key, false) == 0)
2140 {
2141 if (StringToInt(value) == 0)
2142 {
2143 CommandDisable |= DISABLE_ADDBAN;
2144 }
2145 }
2146 else if (strcmp("AutoAddServer", key, false) == 0)
2147 {
2148 AutoAdd = StringToInt(value) == 1;
2149 }
2150 else if (strcmp("Unban", key, false) == 0)
2151 {
2152 if (StringToInt(value) == 0)
2153 {
2154 CommandDisable |= DISABLE_UNBAN;
2155 }
2156 }
2157 else if (strcmp("DatabasePrefix", key, false) == 0)
2158 {
2159 strcopy(DatabasePrefix, sizeof(DatabasePrefix), value);
2160
2161 if (DatabasePrefix[0] == '\0')
2162 {
2163 DatabasePrefix = "sb";
2164 }
2165 }
2166 else if (strcmp("RetryTime", key, false) == 0)
2167 {
2168 RetryTime = StringToFloat(value);
2169 if (RetryTime < 15.0)
2170 {
2171 RetryTime = 15.0;
2172 } else if (RetryTime > 60.0) {
2173 RetryTime = 60.0;
2174 }
2175 }
2176 else if (strcmp("ProcessQueueTime", key, false) == 0)
2177 {
2178 ProcessQueueTime = StringToInt(value);
2179 }
2180 else if (strcmp("BackupConfigs", key, false) == 0)
2181 {
2182 backupConfig = StringToInt(value) == 1;
2183 }
2184 else if (strcmp("EnableAdmins", key, false) == 0)
2185 {
2186 enableAdmins = StringToInt(value) == 1;
2187 }
2188 else if (strcmp("RequireSiteLogin", key, false) == 0)
2189 {
2190 requireSiteLogin = StringToInt(value) == 1;
2191 }
2192 else if (strcmp("ServerID", key, false) == 0)
2193 {
2194 serverID = StringToInt(value);
2195 }
2196 }
2197
2198 case ConfigStateReasons:
2199 {
2200 if (ReasonMenuHandle != INVALID_HANDLE)
2201 {
2202 AddMenuItem(ReasonMenuHandle, key, value);
2203 }
2204 }
2205 case ConfigStateHacking:
2206 {
2207 if (HackingMenuHandle != INVALID_HANDLE)
2208 {
2209 AddMenuItem(HackingMenuHandle, key, value);
2210 }
2211 }
2212 case ConfigStateTime:
2213 {
2214 if (StringToInt(key) > -1 && TimeMenuHandle != INVALID_HANDLE)
2215 {
2216 AddMenuItem(TimeMenuHandle, key, value);
2217 }
2218 }
2219 }
2220 return SMCParse_Continue;
2221}
2222
2223public SMCResult:ReadConfig_EndSection(Handle:smc)
2224{
2225 return SMCParse_Continue;
2226}
2227
2228
2229/*********************************************************
2230 * Ban Player from server
2231 *
2232 * @param client The client index of the player to ban
2233 * @param time The time to ban the player for (in minutes, 0 = permanent)
2234 * @param reason The reason to ban the player from the server
2235 * @noreturn
2236 *********************************************************/
2237public Native_SBBanPlayer(Handle:plugin, numParams)
2238{
2239 new client = GetNativeCell(1);
2240 new target = GetNativeCell(2);
2241 new time = GetNativeCell(3);
2242 new String:reason[128];
2243 GetNativeString(4, reason, 128);
2244
2245 if (reason[0] == '\0')
2246 strcopy(reason, sizeof(reason), "Banned by SourceBans");
2247
2248 if (client && IsClientInGame(client))
2249 {
2250 new AdminId:aid = GetUserAdmin(client);
2251 if (aid == INVALID_ADMIN_ID)
2252 {
2253 ThrowNativeError(SP_ERROR_NATIVE, "Ban Error: Player is not an admin.");
2254 return 0;
2255 }
2256
2257 if (!GetAdminFlag(aid, Admin_Ban))
2258 {
2259 ThrowNativeError(SP_ERROR_NATIVE, "Ban Error: Player does not have BAN flag.");
2260 return 0;
2261 }
2262 }
2263
2264 PrepareBan(client, target, time, reason, sizeof(reason));
2265 return true;
2266}
2267
2268
2269// STOCK FUNCTIONS //
2270
2271public InitializeBackupDB()
2272{
2273 decl String:error[255];
2274 SQLiteDB = SQLite_UseDatabase("sourcebans-queue", error, sizeof(error));
2275 if (SQLiteDB == INVALID_HANDLE)
2276 SetFailState(error);
2277
2278 SQL_LockDatabase(SQLiteDB);
2279 SQL_FastQuery(SQLiteDB, "CREATE TABLE IF NOT EXISTS queue (steam_id TEXT PRIMARY KEY ON CONFLICT REPLACE, time INTEGER, start_time INTEGER, reason TEXT, name TEXT, ip TEXT, admin_id TEXT, admin_ip TEXT);");
2280 SQL_UnlockDatabase(SQLiteDB);
2281}
2282
2283public bool:CreateBan(client, target, time, String:reason[])
2284{
2285 decl String:adminIp[24], String:adminAuth[64];
2286 new admin = client;
2287
2288 // The server is the one calling the ban
2289 if (!admin)
2290 {
2291 if (reason[0] == '\0')
2292 {
2293 // We cannot pop the reason menu if the command was issued from the server
2294 PrintToServer("%s%T", Prefix, "Include Reason", LANG_SERVER);
2295 return false;
2296 }
2297
2298 // setup dummy adminAuth and adminIp for server
2299 strcopy(adminAuth, sizeof(adminAuth), "STEAM_ID_SERVER");
2300 strcopy(adminIp, sizeof(adminIp), ServerIp);
2301 } else {
2302 GetClientIP(admin, adminIp, sizeof(adminIp));
2303 GetClientAuthId(admin, AuthId_Steam2, adminAuth, sizeof(adminAuth));
2304 }
2305
2306 // target information
2307 decl String:ip[24], String:auth[64], String:name[64];
2308
2309 GetClientName(target, name, sizeof(name));
2310 GetClientIP(target, ip, sizeof(ip));
2311 if (!GetClientAuthId(target, AuthId_Steam2, auth, sizeof(auth)))
2312 return false;
2313
2314 new userid = admin ? GetClientUserId(admin) : 0;
2315
2316 // Pack everything into a data pack so we can retain it
2317 new Handle:dataPack = CreateDataPack();
2318 new Handle:reasonPack = CreateDataPack();
2319 WritePackString(reasonPack, reason);
2320
2321 WritePackCell(dataPack, admin);
2322 WritePackCell(dataPack, target);
2323 WritePackCell(dataPack, userid);
2324 WritePackCell(dataPack, GetClientUserId(target));
2325 WritePackCell(dataPack, time);
2326 WritePackCell(dataPack, _:reasonPack);
2327 WritePackString(dataPack, name);
2328 WritePackString(dataPack, auth);
2329 WritePackString(dataPack, ip);
2330 WritePackString(dataPack, adminAuth);
2331 WritePackString(dataPack, adminIp);
2332
2333 ResetPack(dataPack);
2334 ResetPack(reasonPack);
2335
2336 if (reason[0] != '\0')
2337 {
2338 // if we have a valid reason pass move forward with the ban
2339 if (DB != INVALID_HANDLE)
2340 {
2341 UTIL_InsertBan(time, name, auth, ip, reason, adminAuth, adminIp, dataPack);
2342 } else {
2343 UTIL_InsertTempBan(time, name, auth, ip, reason, adminAuth, adminIp, dataPack);
2344 }
2345 } else {
2346 // We need a reason so offer the administrator a menu of reasons
2347 PlayerDataPack[admin] = dataPack;
2348 DisplayMenu(ReasonMenuHandle, admin, MENU_TIME_FOREVER);
2349 ReplyToCommand(admin, "%c[%cSourceBans%c]%c %t", GREEN, NAMECOLOR, GREEN, NAMECOLOR, "Check Menu");
2350 }
2351
2352 Call_StartForward(g_hFwd_OnBanAdded);
2353 Call_PushCell(client);
2354 Call_PushCell(target);
2355 Call_PushCell(time);
2356 Call_PushString(reason);
2357 Call_Finish();
2358
2359 return true;
2360}
2361
2362stock UTIL_InsertBan(time, const String:Name[], const String:Authid[], const String:Ip[], const String:Reason[], const String:AdminAuthid[], const String:AdminIp[], Handle:Pack)
2363{
2364 //new Handle:dummy;
2365 //PruneBans(dummy);
2366 decl String:banName[128];
2367 decl String:banReason[256];
2368 decl String:Query[1024];
2369 SQL_EscapeString(DB, Name, banName, sizeof(banName));
2370 SQL_EscapeString(DB, Reason, banReason, sizeof(banReason));
2371 if (serverID == -1)
2372 {
2373 FormatEx(Query, sizeof(Query), "INSERT INTO %s_bans (ip, authid, name, created, ends, length, reason, aid, adminIp, sid, country) VALUES \
2374 ('%s', '%s', '%s', UNIX_TIMESTAMP(), UNIX_TIMESTAMP() + %d, %d, '%s', IFNULL((SELECT aid FROM %s_admins WHERE authid = '%s' OR authid REGEXP '^STEAM_[0-9]:%s$'),'0'), '%s', \
2375 (SELECT sid FROM %s_servers WHERE ip = '%s' AND port = '%s' LIMIT 0,1), ' ')",
2376 DatabasePrefix, Ip, Authid, banName, (time * 60), (time * 60), banReason, DatabasePrefix, AdminAuthid, AdminAuthid[8], AdminIp, DatabasePrefix, ServerIp, ServerPort);
2377 } else {
2378 FormatEx(Query, sizeof(Query), "INSERT INTO %s_bans (ip, authid, name, created, ends, length, reason, aid, adminIp, sid, country) VALUES \
2379 ('%s', '%s', '%s', UNIX_TIMESTAMP(), UNIX_TIMESTAMP() + %d, %d, '%s', IFNULL((SELECT aid FROM %s_admins WHERE authid = '%s' OR authid REGEXP '^STEAM_[0-9]:%s$'),'0'), '%s', \
2380 %d, ' ')",
2381 DatabasePrefix, Ip, Authid, banName, (time * 60), (time * 60), banReason, DatabasePrefix, AdminAuthid, AdminAuthid[8], AdminIp, serverID);
2382 }
2383
2384 SQL_TQuery(DB, VerifyInsert, Query, Pack, DBPrio_High);
2385}
2386
2387stock UTIL_InsertTempBan(time, const String:name[], const String:auth[], const String:ip[], const String:reason[], const String:adminAuth[], const String:adminIp[], Handle:dataPack)
2388{
2389 ReadPackCell(dataPack); // admin index
2390 new client = ReadPackCell(dataPack);
2391 ReadPackCell(dataPack); // admin userid
2392 ReadPackCell(dataPack); // target userid
2393 ReadPackCell(dataPack); // time
2394 new Handle:reasonPack = Handle:ReadPackCell(dataPack);
2395 if (reasonPack != INVALID_HANDLE)
2396 {
2397 CloseHandle(reasonPack);
2398 }
2399 CloseHandle(dataPack);
2400
2401 // we add a temporary ban and then add the record into the queue to be processed when the database is available
2402 decl String:buffer[50];
2403 Format(buffer, sizeof(buffer), "banid %d %s", ProcessQueueTime, auth);
2404 ServerCommand(buffer);
2405 if (IsClientInGame(client))
2406 KickClient(client, "%t", "Banned Check Site", WebsiteAddress);
2407
2408 decl String:banName[128];
2409 decl String:banReason[256];
2410 decl String:query[512];
2411 SQL_EscapeString(SQLiteDB, name, banName, sizeof(banName));
2412 SQL_EscapeString(SQLiteDB, reason, banReason, sizeof(banReason));
2413 FormatEx(query, sizeof(query), "INSERT INTO queue VALUES ('%s', %i, %i, '%s', '%s', '%s', '%s', '%s')",
2414 auth, time, GetTime(), banReason, banName, ip, adminAuth, adminIp);
2415 SQL_TQuery(SQLiteDB, ErrorCheckCallback, query);
2416}
2417
2418stock CheckLoadAdmins()
2419{
2420 for (new i = 1; i <= MaxClients; i++)
2421 {
2422 if (IsClientInGame(i) && IsClientAuthorized(i))
2423 {
2424 RunAdminCacheChecks(i);
2425 NotifyPostAdminCheck(i);
2426 }
2427 }
2428}
2429
2430stock InsertServerInfo()
2431{
2432 if (DB == INVALID_HANDLE)
2433 {
2434 return;
2435 }
2436
2437 decl String:query[100], pieces[4];
2438 new longip = GetConVarInt(CvarHostIp);
2439 pieces[0] = (longip >> 24) & 0x000000FF;
2440 pieces[1] = (longip >> 16) & 0x000000FF;
2441 pieces[2] = (longip >> 8) & 0x000000FF;
2442 pieces[3] = longip & 0x000000FF;
2443 FormatEx(ServerIp, sizeof(ServerIp), "%d.%d.%d.%d", pieces[0], pieces[1], pieces[2], pieces[3]);
2444 GetConVarString(CvarPort, ServerPort, sizeof(ServerPort));
2445
2446 if (AutoAdd != false)
2447 {
2448 FormatEx(query, sizeof(query), "SELECT sid FROM %s_servers WHERE ip = '%s' AND port = '%s'", DatabasePrefix, ServerIp, ServerPort);
2449 SQL_TQuery(DB, ServerInfoCallback, query);
2450 }
2451}
2452
2453stock PrepareBan(client, target, time, String:reason[], size)
2454{
2455 #if defined DEBUG
2456 LogToFile(logFile, "PrepareBan()");
2457 #endif
2458 if (!target || !IsClientInGame(target))
2459 return;
2460 decl String:authid[64], String:name[32], String:bannedSite[512];
2461 if (!GetClientAuthId(target, AuthId_Steam2, authid, sizeof(authid)))
2462 return;
2463 GetClientName(target, name, sizeof(name));
2464
2465
2466 if (CreateBan(client, target, time, reason))
2467 {
2468 if (!time)
2469 {
2470 if (reason[0] == '\0')
2471 {
2472 ShowActivity(client, "%t", "Permabanned player", name);
2473 } else {
2474 ShowActivity(client, "%t", "Permabanned player reason", name, reason);
2475 }
2476 } else {
2477 if (reason[0] == '\0')
2478 {
2479 ShowActivity(client, "%t", "Banned player", name, time);
2480 } else {
2481 ShowActivity(client, "%t", "Banned player reason", name, time, reason);
2482 }
2483 }
2484 LogAction(client, target, "\"%L\" banned \"%L\" (minutes \"%d\") (reason \"%s\")", client, target, time, reason);
2485
2486 if (time > 5 || time == 0)
2487 time = 5;
2488 Format(bannedSite, sizeof(bannedSite), "%T", "Banned Check Site", target, WebsiteAddress);
2489 BanClient(target, time, BANFLAG_AUTO, bannedSite, bannedSite, "sm_ban", client);
2490 }
2491
2492 g_BanTarget[client] = -1;
2493 g_BanTime[client] = -1;
2494}
2495
2496stock ReadConfig()
2497{
2498 InitializeConfigParser();
2499
2500 if (ConfigParser == INVALID_HANDLE)
2501 {
2502 return;
2503 }
2504
2505 decl String:ConfigFile[PLATFORM_MAX_PATH];
2506 BuildPath(Path_SM, ConfigFile, sizeof(ConfigFile), "configs/sourcebans/sourcebans.cfg");
2507
2508 if (FileExists(ConfigFile))
2509 {
2510 InternalReadConfig(ConfigFile);
2511 PrintToServer("%sLoading configs/sourcebans.cfg config file", Prefix);
2512 } else {
2513 decl String:Error[PLATFORM_MAX_PATH + 64];
2514 FormatEx(Error, sizeof(Error), "%sFATAL *** ERROR *** can not find %s", Prefix, ConfigFile);
2515 LogToFile(logFile, "FATAL *** ERROR *** can not find %s", ConfigFile);
2516 SetFailState(Error);
2517 }
2518}
2519
2520stock ResetSettings()
2521{
2522 CommandDisable = 0;
2523
2524 ResetMenu();
2525 ReadConfig();
2526}
2527
2528stock ParseBackupConfig_Overrides()
2529{
2530 new Handle:hKV = CreateKeyValues("SB_Overrides");
2531 if (!FileToKeyValues(hKV, overridesLoc))
2532 return;
2533
2534 if (!KvGotoFirstSubKey(hKV))
2535 return;
2536
2537 decl String:sSection[16], String:sFlags[32], String:sName[64];
2538 decl OverrideType:type;
2539 do
2540 {
2541 KvGetSectionName(hKV, sSection, sizeof(sSection));
2542 if (StrEqual(sSection, "override_commands"))
2543 type = Override_Command;
2544 else if (StrEqual(sSection, "override_groups"))
2545 type = Override_CommandGroup;
2546 else
2547 continue;
2548
2549 if (KvGotoFirstSubKey(hKV, false))
2550 {
2551 do
2552 {
2553 KvGetSectionName(hKV, sName, sizeof(sName));
2554 KvGetString(hKV, NULL_STRING, sFlags, sizeof(sFlags));
2555 AddCommandOverride(sName, type, ReadFlagString(sFlags));
2556 #if defined _DEBUG
2557 PrintToServer("Adding override (%s, %s, %s)", sSection, sName, sFlags);
2558 #endif
2559 } while (KvGotoNextKey(hKV, false));
2560 KvGoBack(hKV);
2561 }
2562 }
2563 while (KvGotoNextKey(hKV));
2564 CloseHandle(hKV);
2565}
2566
2567stock AdminFlag:CreateFlagLetters()
2568{
2569 new AdminFlag:FlagLetters[FLAG_LETTERS_SIZE];
2570
2571 FlagLetters['a'-'a'] = Admin_Reservation;
2572 FlagLetters['b'-'a'] = Admin_Generic;
2573 FlagLetters['c'-'a'] = Admin_Kick;
2574 FlagLetters['d'-'a'] = Admin_Ban;
2575 FlagLetters['e'-'a'] = Admin_Unban;
2576 FlagLetters['f'-'a'] = Admin_Slay;
2577 FlagLetters['g'-'a'] = Admin_Changemap;
2578 FlagLetters['h'-'a'] = Admin_Convars;
2579 FlagLetters['i'-'a'] = Admin_Config;
2580 FlagLetters['j'-'a'] = Admin_Chat;
2581 FlagLetters['k'-'a'] = Admin_Vote;
2582 FlagLetters['l'-'a'] = Admin_Password;
2583 FlagLetters['m'-'a'] = Admin_RCON;
2584 FlagLetters['n'-'a'] = Admin_Cheats;
2585 FlagLetters['o'-'a'] = Admin_Custom1;
2586 FlagLetters['p'-'a'] = Admin_Custom2;
2587 FlagLetters['q'-'a'] = Admin_Custom3;
2588 FlagLetters['r'-'a'] = Admin_Custom4;
2589 FlagLetters['s'-'a'] = Admin_Custom5;
2590 FlagLetters['t'-'a'] = Admin_Custom6;
2591 FlagLetters['z'-'a'] = Admin_Root;
2592
2593 return FlagLetters;
2594}
2595
2596stock AccountForLateLoading()
2597{
2598 decl String:auth[30];
2599 for (new i = 1; i <= GetMaxClients(); i++)
2600 {
2601 if (IsClientConnected(i) && !IsFakeClient(i))
2602 {
2603 PlayerStatus[i] = false;
2604 }
2605 if (IsClientInGame(i) && !IsFakeClient(i) && IsClientAuthorized(i) && GetClientAuthId(i, AuthId_Steam2, auth, sizeof(auth)))
2606 {
2607 OnClientAuthorized(i, auth);
2608 }
2609 }
2610}
2611
2612//Yarr!