· 6 years ago · Mar 12, 2019, 05:48 PM
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// SourceComms 0.9.266
21// Copyright (C) 2013-2014 Alexandr Duplishchev
22// Licensed under GNU GPL version 3, or later.
23// Page: <https://forums.alliedmods.net/showthread.php?p=1883705> - <https://github.com/d-ai/SourceComms>
24//
25// *************************************************************************
26
27#pragma semicolon 1
28
29#include <sourcemod>
30#include <basecomm>
31#include <sourcecomms>
32
33#undef REQUIRE_PLUGIN
34#include <adminmenu>
35
36#define UNBLOCK_FLAG ADMFLAG_CHEATS
37#define DATABASE "sourcebans"
38
39// #define DEBUG
40// #define LOG_QUERIES
41
42// Do not edit below this line //
43//-----------------------------//
44
45#define PLUGIN_VERSION "1.6.3"
46#define PREFIX "\x04[SourceComms++]\x01 "
47
48#define MAX_TIME_MULTI 30 // maximum mass-target punishment length
49// session mute will expire after this if it hasn't already (fallback)
50#define SESSION_MUTE_FALLBACK 120 * 60
51
52#define NOW 0
53#define TYPE_TEMP_SHIFT 10
54
55#define MAX_REASONS 32
56#define DISPLAY_SIZE 64
57#define REASON_SIZE 192
58
59new iNumReasons;
60new String:g_sReasonDisplays[MAX_REASONS][DISPLAY_SIZE], String:g_sReasonKey[MAX_REASONS][REASON_SIZE];
61
62#define MAX_TIMES 32
63new iNumTimes, g_iTimeMinutes[MAX_TIMES];
64new String:g_sTimeDisplays[MAX_TIMES][DISPLAY_SIZE];
65
66enum State/* ConfigState */
67{
68 ConfigStateNone = 0,
69 ConfigStateConfig,
70 ConfigStateReasons,
71 ConfigStateTimes,
72 ConfigStateServers,
73}
74enum DatabaseState/* Database connection state */
75{
76 DatabaseState_None = 0,
77 DatabaseState_Wait,
78 DatabaseState_Connecting,
79 DatabaseState_Connected,
80}
81
82new DatabaseState:g_DatabaseState;
83new g_iConnectLock = 0;
84new g_iSequence = 0;
85
86new State:ConfigState;
87new Handle:ConfigParser;
88
89new Handle:hTopMenu = INVALID_HANDLE;
90
91/* Cvar handle*/
92new Handle:CvarHostIp;
93new Handle:CvarPort;
94
95new String:ServerIp[24];
96new String:ServerPort[7];
97
98/* Database handle */
99new Handle:g_hDatabase;
100new Handle:SQLiteDB;
101
102new String:DatabasePrefix[10] = "sb";
103
104/* Timer handles */
105new Handle:g_hPlayerRecheck[MAXPLAYERS + 1] = { INVALID_HANDLE, ... };
106new Handle:g_hGagExpireTimer[MAXPLAYERS + 1] = { INVALID_HANDLE, ... };
107new Handle:g_hMuteExpireTimer[MAXPLAYERS + 1] = { INVALID_HANDLE, ... };
108
109
110/* Log Stuff */
111#if defined LOG_QUERIES
112new String:logQuery[256];
113#endif
114
115new Float:RetryTime = 15.0;
116new DefaultTime = 30;
117new DisUBImCheck = 0;
118new ConsoleImmunity = 0;
119new ConfigMaxLength = 0;
120new ConfigWhiteListOnly = 0;
121new serverID = 0;
122
123/* List menu */
124enum PeskyPanels
125{
126 curTarget,
127 curIndex,
128 viewingMute,
129 viewingGag,
130 viewingList,
131}
132new g_iPeskyPanels[MAXPLAYERS + 1][PeskyPanels];
133
134new bool:g_bPlayerStatus[MAXPLAYERS + 1]; // Player block check status
135new String:g_sName[MAXPLAYERS + 1][MAX_NAME_LENGTH];
136
137new bType:g_MuteType[MAXPLAYERS + 1];
138new g_iMuteTime[MAXPLAYERS + 1];
139new g_iMuteLength[MAXPLAYERS + 1]; // in sec
140new g_iMuteLevel[MAXPLAYERS + 1]; // immunity level of admin
141new String:g_sMuteAdminName[MAXPLAYERS + 1][MAX_NAME_LENGTH];
142new String:g_sMuteReason[MAXPLAYERS + 1][256];
143new String:g_sMuteAdminAuth[MAXPLAYERS + 1][64];
144
145new bType:g_GagType[MAXPLAYERS + 1];
146new g_iGagTime[MAXPLAYERS + 1];
147new g_iGagLength[MAXPLAYERS + 1]; // in sec
148new g_iGagLevel[MAXPLAYERS + 1]; // immunity level of admin
149new String:g_sGagAdminName[MAXPLAYERS + 1][MAX_NAME_LENGTH];
150new String:g_sGagReason[MAXPLAYERS + 1][256];
151new String:g_sGagAdminAuth[MAXPLAYERS + 1][64];
152
153new Handle:g_hServersWhiteList = INVALID_HANDLE;
154
155// Forward
156new Handle:g_hFwd_OnPlayerPunished;
157
158public Plugin:myinfo =
159{
160 name = "SourceBans++: SourceComms",
161 author = "Alex, SourceBans++ Dev Team",
162 description = "Advanced punishments management for the Source engine in SourceBans style",
163 version = PLUGIN_VERSION,
164 url = "https://sbpp.github.io"
165};
166
167public APLRes:AskPluginLoad2(Handle:myself, bool:late, String:error[], err_max)
168{
169 CreateNative("SourceComms_SetClientMute", Native_SetClientMute);
170 CreateNative("SourceComms_SetClientGag", Native_SetClientGag);
171 CreateNative("SourceComms_GetClientMuteType", Native_GetClientMuteType);
172 CreateNative("SourceComms_GetClientGagType", Native_GetClientGagType);
173
174 g_hFwd_OnPlayerPunished = CreateGlobalForward("SourceComms_OnBlockAdded", ET_Ignore, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_String);
175
176 MarkNativeAsOptional("SQL_SetCharset");
177 RegPluginLibrary("sourcecomms++");
178 return APLRes_Success;
179}
180
181public OnPluginStart()
182{
183 LoadTranslations("common.phrases");
184 LoadTranslations("sourcecomms.phrases");
185
186 new Handle:hTemp = INVALID_HANDLE;
187 if (LibraryExists("adminmenu") && ((hTemp = GetAdminTopMenu()) != INVALID_HANDLE))
188 OnAdminMenuReady(hTemp);
189
190 CvarHostIp = FindConVar("hostip");
191 CvarPort = FindConVar("hostport");
192 g_hServersWhiteList = CreateArray();
193
194 CreateConVar("sourcecomms_version", PLUGIN_VERSION, _, FCVAR_SPONLY | FCVAR_REPLICATED | FCVAR_NOTIFY);
195 AddCommandListener(CommandCallback, "sm_gag");
196 AddCommandListener(CommandCallback, "sm_mute");
197 AddCommandListener(CommandCallback, "sm_silence");
198 AddCommandListener(CommandCallback, "sm_ungag");
199 AddCommandListener(CommandCallback, "sm_unmute");
200 AddCommandListener(CommandCallback, "sm_unsilence");
201 RegServerCmd("sc_fw_block", FWBlock, "Blocking player comms by command from sourceban web site");
202 RegServerCmd("sc_fw_ungag", FWUngag, "Ungagging player by command from sourceban web site");
203 RegServerCmd("sc_fw_unmute", FWUnmute, "Unmuting player by command from sourceban web site");
204 RegConsoleCmd("sm_comms", CommandComms, "Shows current player communications status");
205
206 HookEvent("player_changename", Event_OnPlayerName, EventHookMode_Post);
207
208 #if defined LOG_QUERIES
209 BuildPath(Path_SM, logQuery, sizeof(logQuery), "logs/sourcecomms-q.log");
210 #endif
211
212 #if defined DEBUG
213 PrintToServer("Sourcecomms plugin loading. Version %s", PLUGIN_VERSION);
214 #endif
215
216 // Catch config error
217 if (!SQL_CheckConfig(DATABASE))
218 {
219 SetFailState("Database failure: could not find database config: %s", DATABASE);
220 return;
221 }
222 DB_Connect();
223 InitializeBackupDB();
224
225 ServerInfo();
226
227 for (new client = 1; client <= MaxClients; client++)
228 {
229 if (IsClientInGame(client) && IsClientAuthorized(client))
230 OnClientPostAdminCheck(client);
231 }
232}
233
234public OnLibraryRemoved(const String:name[])
235{
236 if (StrEqual(name, "adminmenu"))
237 hTopMenu = INVALID_HANDLE;
238}
239
240public OnMapStart()
241{
242 ReadConfig();
243}
244
245public OnMapEnd()
246{
247 // Clean up on map end just so we can start a fresh connection when we need it later.
248 // Also it is necessary for using SQL_SetCharset
249 if (g_hDatabase)
250 CloseHandle(g_hDatabase);
251
252 g_hDatabase = INVALID_HANDLE;
253}
254
255
256// CLIENT CONNECTION FUNCTIONS //
257
258public OnClientDisconnect(client)
259{
260 if (g_hPlayerRecheck[client] != INVALID_HANDLE && CloseHandle(g_hPlayerRecheck[client]))
261 g_hPlayerRecheck[client] = INVALID_HANDLE;
262
263 CloseMuteExpireTimer(client);
264 CloseGagExpireTimer(client);
265}
266
267public bool:OnClientConnect(client, String:rejectmsg[], maxlen)
268{
269 g_bPlayerStatus[client] = false;
270 return true;
271}
272
273public OnClientConnected(client)
274{
275 g_sName[client][0] = '\0';
276
277 MarkClientAsUnMuted(client);
278 MarkClientAsUnGagged(client);
279}
280
281public OnClientPostAdminCheck(client)
282{
283 decl String:clientAuth[64];
284 GetClientAuthId(client, AuthId_Steam2, clientAuth, sizeof(clientAuth));
285 GetClientName(client, g_sName[client], sizeof(g_sName[]));
286
287 /* Do not check bots or check player with lan steamid. */
288 if (clientAuth[0] == 'B' || clientAuth[9] == 'L' || !DB_Connect())
289 {
290 g_bPlayerStatus[client] = true;
291 return;
292 }
293
294 if (client > 0 && IsClientInGame(client) && !IsFakeClient(client))
295 {
296 // if plugin was late loaded
297 if (BaseComm_IsClientMuted(client))
298 {
299 MarkClientAsMuted(client);
300 }
301 if (BaseComm_IsClientGagged(client))
302 {
303 MarkClientAsGagged(client);
304 }
305
306 decl String:sClAuthYZEscaped[sizeof(clientAuth) * 2 + 1];
307 SQL_EscapeString(g_hDatabase, clientAuth[8], sClAuthYZEscaped, sizeof(sClAuthYZEscaped));
308
309 decl String:Query[4096];
310 FormatEx(Query, sizeof(Query),
311 "SELECT (c.ends - UNIX_TIMESTAMP()) AS remaining, \
312 c.length, c.type, c.created, c.reason, a.user, \
313 IF (a.immunity>=g.immunity, a.immunity, IFNULL(g.immunity,0)) AS immunity, \
314 c.aid, c.sid, a.authid \
315 FROM %s_comms AS c \
316 LEFT JOIN %s_admins AS a ON a.aid = c.aid \
317 LEFT JOIN %s_srvgroups AS g ON g.name = a.srv_group \
318 WHERE RemoveType IS NULL \
319 AND c.authid REGEXP '^STEAM_[0-9]:%s$' \
320 AND (length = '0' OR ends > UNIX_TIMESTAMP())",
321 DatabasePrefix, DatabasePrefix, DatabasePrefix, sClAuthYZEscaped);
322 #if defined LOG_QUERIES
323 LogToFile(logQuery, "OnClientPostAdminCheck for: %s. QUERY: %s", clientAuth, Query);
324 #endif
325 SQL_TQuery(g_hDatabase, Query_VerifyBlock, Query, GetClientUserId(client), DBPrio_High);
326 }
327}
328
329
330// OTHER CLIENT CODE //
331
332public Action:Event_OnPlayerName(Handle:event, const String:name[], bool:dontBroadcast)
333{
334 new client = GetClientOfUserId(GetEventInt(event, "userid"));
335 if (client > 0 && IsClientInGame(client))
336 GetEventString(event, "newname", g_sName[client], sizeof(g_sName[]));
337}
338
339public BaseComm_OnClientMute(client, bool:muteState)
340{
341 if (client > 0 && client <= MaxClients)
342 {
343 if (muteState)
344 {
345 if (g_MuteType[client] == bNot)
346 {
347 MarkClientAsMuted(client, _, _, _, _, _, "Muted through BaseComm natives");
348 SavePunishment(_, client, TYPE_MUTE, _, "Muted through BaseComm natives");
349 }
350 }
351 else
352 {
353 if (g_MuteType[client] > bNot)
354 {
355 MarkClientAsUnMuted(client);
356 }
357 }
358 }
359}
360
361public BaseComm_OnClientGag(client, bool:gagState)
362{
363 if (client > 0 && client <= MaxClients)
364 {
365 if (gagState)
366 {
367 if (g_GagType[client] == bNot)
368 {
369 MarkClientAsGagged(client, _, _, _, _, _, "Gagged through BaseComm natives");
370 SavePunishment(_, client, TYPE_GAG, _, "Gagged through BaseComm natives");
371 }
372 }
373 else
374 {
375 if (g_GagType[client] > bNot)
376 {
377 MarkClientAsUnGagged(client);
378 }
379 }
380 }
381}
382
383// COMMAND CODE //
384
385public Action:CommandComms(client, args)
386{
387 if (!client)
388 {
389 ReplyToCommand(client, "%s%t", PREFIX, "CommandComms_na");
390 return Plugin_Continue;
391 }
392
393 if (g_MuteType[client] > bNot || g_GagType[client] > bNot)
394 AdminMenu_ListTarget(client, client, 0);
395 else
396 ReplyToCommand(client, "%s%t", PREFIX, "CommandComms_nb");
397
398 return Plugin_Handled;
399}
400
401public Action:FWBlock(args)
402{
403 decl String:arg_string[256];
404 new String:sArg[3][64];
405 GetCmdArgString(arg_string, sizeof(arg_string));
406
407 decl type, length;
408 if (ExplodeString(arg_string, " ", sArg, 3, 64) != 3 || !StringToIntEx(sArg[0], type) || type < 1 || type > 3 || !StringToIntEx(sArg[1], length))
409 {
410 LogError("Wrong usage of sc_fw_block");
411 return Plugin_Stop;
412 }
413
414 LogMessage("Received block command from web: steam %s, type %d, length %d", sArg[2], type, length);
415
416 decl String:clientAuth[64];
417 for (new i = 1; i <= MaxClients; i++)
418 {
419 if (IsClientInGame(i) && IsClientAuthorized(i) && !IsFakeClient(i))
420 {
421 GetClientAuthId(i, AuthId_Steam2, clientAuth, sizeof(clientAuth));
422 if (strcmp(clientAuth, sArg[2], false) == 0)
423 {
424 #if defined DEBUG
425 PrintToServer("Catched %s for blocking from web", clientAuth);
426 #endif
427
428 switch (type) {
429 case TYPE_MUTE:setMute(i, length, clientAuth);
430 case TYPE_GAG:setGag(i, length, clientAuth);
431 case TYPE_SILENCE: { setMute(i, length, clientAuth); setGag(i, length, clientAuth); }
432 }
433 break;
434 }
435 }
436 }
437
438 return Plugin_Handled;
439}
440
441public Action:FWUngag(args)
442{
443 decl String:arg_string[256];
444 new String:sArg[1][64];
445 GetCmdArgString(arg_string, sizeof(arg_string));
446 if (!ExplodeString(arg_string, " ", sArg, 1, 64))
447 {
448 LogError("Wrong usage of sc_fw_ungag");
449 return Plugin_Stop;
450 }
451
452 LogMessage("Received ungag command from web: steam %s", sArg[0]);
453
454 for (new i = 1; i <= MaxClients; i++)
455 {
456 if (IsClientInGame(i) && IsClientAuthorized(i) && !IsFakeClient(i))
457 {
458 decl String:clientAuth[64];
459 GetClientAuthId(i, AuthId_Steam2, clientAuth, sizeof(clientAuth));
460 if (strcmp(clientAuth, sArg[0], false) == 0)
461 {
462 #if defined DEBUG
463 PrintToServer("Catched %s for ungagging from web", clientAuth);
464 #endif
465
466 if (g_GagType[i] > bNot)
467 {
468 PerformUnGag(i);
469 PrintToChat(i, "%s%t", PREFIX, "FWUngag");
470 LogMessage("%s is ungagged from web", clientAuth);
471 }
472 else
473 LogError("Can't ungag %s from web, it isn't gagged", clientAuth);
474 break;
475 }
476 }
477 }
478 return Plugin_Handled;
479}
480
481public Action:FWUnmute(args)
482{
483 decl String:arg_string[256];
484 new String:sArg[1][64];
485 GetCmdArgString(arg_string, sizeof(arg_string));
486 if (!ExplodeString(arg_string, " ", sArg, 1, 64))
487 {
488 LogError("Wrong usage of sc_fw_ungag");
489 return Plugin_Stop;
490 }
491
492 LogMessage("Received unmute command from web: steam %s", sArg[0]);
493
494 for (new i = 1; i <= MaxClients; i++)
495 {
496 if (IsClientInGame(i) && IsClientAuthorized(i) && !IsFakeClient(i))
497 {
498 decl String:clientAuth[64];
499 GetClientAuthId(i, AuthId_Steam2, clientAuth, sizeof(clientAuth));
500 if (strcmp(clientAuth, sArg[0], false) == 0)
501 {
502 #if defined DEBUG
503 PrintToServer("Catched %s for unmuting from web", clientAuth);
504 #endif
505
506 if (g_MuteType[i] > bNot)
507 {
508 PerformUnMute(i);
509 PrintToChat(i, "%s%t", PREFIX, "FWUnmute");
510 LogMessage("%s is unmuted from web", clientAuth);
511 }
512 else
513 LogError("Can't unmute %s from web, it isn't muted", clientAuth);
514 break;
515 }
516 }
517 }
518 return Plugin_Handled;
519}
520
521
522public Action:CommandCallback(client, const String:command[], args)
523{
524 if (client && !CheckCommandAccess(client, command, ADMFLAG_CHAT))
525 return Plugin_Continue;
526
527 new type;
528 if (StrEqual(command, "sm_gag", false))
529 type = TYPE_GAG;
530 else if (StrEqual(command, "sm_mute", false))
531 type = TYPE_MUTE;
532 else if (StrEqual(command, "sm_ungag", false))
533 type = TYPE_UNGAG;
534 else if (StrEqual(command, "sm_unmute", false))
535 type = TYPE_UNMUTE;
536 else if (StrEqual(command, "sm_silence", false))
537 type = TYPE_SILENCE;
538 else if (StrEqual(command, "sm_unsilence", false))
539 type = TYPE_UNSILENCE;
540 else
541 return Plugin_Stop;
542
543 if (args < 1)
544 {
545 ReplyToCommand(client, "%sUsage: %s <#userid|name> %s", PREFIX, command, type <= TYPE_SILENCE ? "[time|0] [reason]" : "[reason]");
546 if (type <= TYPE_SILENCE)
547 ReplyToCommand(client, "%sUsage: %s <#userid|name> [reason]", PREFIX, command);
548 return Plugin_Stop;
549 }
550
551 decl String:sBuffer[256];
552 GetCmdArgString(sBuffer, sizeof(sBuffer));
553
554 if (type <= TYPE_SILENCE)
555 CreateBlock(client, _, _, type, _, sBuffer);
556 else
557 ProcessUnBlock(client, _, type, _, sBuffer);
558
559 return Plugin_Stop;
560}
561
562
563// MENU CODE //
564
565public OnAdminMenuReady(Handle:topmenu)
566{
567 /* Block us from being called twice */
568 if (topmenu == hTopMenu)
569 return;
570
571 /* Save the Handle */
572 hTopMenu = topmenu;
573
574 new TopMenuObject:MenuObject = AddToTopMenu(hTopMenu, "sourcecomm_cmds", TopMenuObject_Category, Handle_Commands, INVALID_TOPMENUOBJECT);
575 if (MenuObject == INVALID_TOPMENUOBJECT)
576 return;
577
578 AddToTopMenu(hTopMenu, "sourcecomm_gag", TopMenuObject_Item, Handle_MenuGag, MenuObject, "sm_gag", ADMFLAG_CHAT);
579 AddToTopMenu(hTopMenu, "sourcecomm_ungag", TopMenuObject_Item, Handle_MenuUnGag, MenuObject, "sm_ungag", ADMFLAG_CHAT);
580 AddToTopMenu(hTopMenu, "sourcecomm_mute", TopMenuObject_Item, Handle_MenuMute, MenuObject, "sm_mute", ADMFLAG_CHAT);
581 AddToTopMenu(hTopMenu, "sourcecomm_unmute", TopMenuObject_Item, Handle_MenuUnMute, MenuObject, "sm_unmute", ADMFLAG_CHAT);
582 AddToTopMenu(hTopMenu, "sourcecomm_silence", TopMenuObject_Item, Handle_MenuSilence, MenuObject, "sm_silence", ADMFLAG_CHAT);
583 AddToTopMenu(hTopMenu, "sourcecomm_unsilence", TopMenuObject_Item, Handle_MenuUnSilence, MenuObject, "sm_unsilence", ADMFLAG_CHAT);
584 AddToTopMenu(hTopMenu, "sourcecomm_list", TopMenuObject_Item, Handle_MenuList, MenuObject, "sm_commlist", ADMFLAG_CHAT);
585}
586
587public Handle_Commands(Handle:menu, TopMenuAction:action, TopMenuObject:object_id, param1, String:buffer[], maxlength)
588{
589 switch (action)
590 {
591 case TopMenuAction_DisplayOption:
592 Format(buffer, maxlength, "%T", "AdminMenu_Main", param1);
593 case TopMenuAction_DisplayTitle:
594 Format(buffer, maxlength, "%T", "AdminMenu_Select_Main", param1);
595 }
596}
597
598public Handle_MenuGag(Handle:menu, TopMenuAction:action, TopMenuObject:object_id, param1, String:buffer[], maxlength)
599{
600 if (action == TopMenuAction_DisplayOption)
601 Format(buffer, maxlength, "%T", "AdminMenu_Gag", param1);
602 else if (action == TopMenuAction_SelectOption)
603 AdminMenu_Target(param1, TYPE_GAG);
604}
605
606public Handle_MenuUnGag(Handle:menu, TopMenuAction:action, TopMenuObject:object_id, param1, String:buffer[], maxlength)
607{
608 if (action == TopMenuAction_DisplayOption)
609 Format(buffer, maxlength, "%T", "AdminMenu_UnGag", param1);
610 else if (action == TopMenuAction_SelectOption)
611 AdminMenu_Target(param1, TYPE_UNGAG);
612}
613
614public Handle_MenuMute(Handle:menu, TopMenuAction:action, TopMenuObject:object_id, param1, String:buffer[], maxlength)
615{
616 if (action == TopMenuAction_DisplayOption)
617 Format(buffer, maxlength, "%T", "AdminMenu_Mute", param1);
618 else if (action == TopMenuAction_SelectOption)
619 AdminMenu_Target(param1, TYPE_MUTE);
620}
621
622public Handle_MenuUnMute(Handle:menu, TopMenuAction:action, TopMenuObject:object_id, param1, String:buffer[], maxlength)
623{
624 if (action == TopMenuAction_DisplayOption)
625 Format(buffer, maxlength, "%T", "AdminMenu_UnMute", param1);
626 else if (action == TopMenuAction_SelectOption)
627 AdminMenu_Target(param1, TYPE_UNMUTE);
628}
629
630public Handle_MenuSilence(Handle:menu, TopMenuAction:action, TopMenuObject:object_id, param1, String:buffer[], maxlength)
631{
632 if (action == TopMenuAction_DisplayOption)
633 Format(buffer, maxlength, "%T", "AdminMenu_Silence", param1);
634 else if (action == TopMenuAction_SelectOption)
635 AdminMenu_Target(param1, TYPE_SILENCE);
636}
637
638public Handle_MenuUnSilence(Handle:menu, TopMenuAction:action, TopMenuObject:object_id, param1, String:buffer[], maxlength)
639{
640 if (action == TopMenuAction_DisplayOption)
641 Format(buffer, maxlength, "%T", "AdminMenu_UnSilence", param1);
642 else if (action == TopMenuAction_SelectOption)
643 AdminMenu_Target(param1, TYPE_UNSILENCE);
644}
645
646public Handle_MenuList(Handle:menu, TopMenuAction:action, TopMenuObject:object_id, param1, String:buffer[], maxlength)
647{
648 if (action == TopMenuAction_DisplayOption)
649 Format(buffer, maxlength, "%T", "AdminMenu_List", param1);
650 else if (action == TopMenuAction_SelectOption)
651 {
652 g_iPeskyPanels[param1][viewingList] = false;
653 AdminMenu_List(param1, 0);
654 }
655}
656
657AdminMenu_Target(client, type)
658{
659 decl String:Title[192], String:Option[32];
660 switch (type)
661 {
662 case TYPE_GAG:
663 Format(Title, sizeof(Title), "%T", "AdminMenu_Select_Gag", client);
664 case TYPE_MUTE:
665 Format(Title, sizeof(Title), "%T", "AdminMenu_Select_Mute", client);
666 case TYPE_SILENCE:
667 Format(Title, sizeof(Title), "%T", "AdminMenu_Select_Silence", client);
668 case TYPE_UNGAG:
669 Format(Title, sizeof(Title), "%T", "AdminMenu_Select_Ungag", client);
670 case TYPE_UNMUTE:
671 Format(Title, sizeof(Title), "%T", "AdminMenu_Select_Unmute", client);
672 case TYPE_UNSILENCE:
673 Format(Title, sizeof(Title), "%T", "AdminMenu_Select_Unsilence", client);
674 }
675
676 new Handle:hMenu = CreateMenu(MenuHandler_MenuTarget); // Common menu - players list. Almost full for blocking, and almost empty for unblocking
677 SetMenuTitle(hMenu, Title);
678 SetMenuExitBackButton(hMenu, true);
679
680 new iClients;
681 if (type <= 3) // Mute, gag, silence
682 {
683 for (new i = 1; i <= MaxClients; i++)
684 {
685 if (IsClientInGame(i) && !IsFakeClient(i))
686 {
687 switch (type)
688 {
689 case TYPE_MUTE:
690 if (g_MuteType[i] > bNot)
691 continue;
692 case TYPE_GAG:
693 if (g_GagType[i] > bNot)
694 continue;
695 case TYPE_SILENCE:
696 if (g_MuteType[i] > bNot || g_GagType[i] > bNot)
697 continue;
698 }
699 iClients++;
700 strcopy(Title, sizeof(Title), g_sName[i]);
701 AdminMenu_GetPunishPhrase(client, i, Title, sizeof(Title));
702 Format(Option, sizeof(Option), "%d %d", GetClientUserId(i), type);
703 AddMenuItem(hMenu, Option, Title, (CanUserTarget(client, i) ? ITEMDRAW_DEFAULT : ITEMDRAW_DISABLED));
704 }
705 }
706 }
707 else // UnMute, ungag, unsilence
708 {
709 for (new i = 1; i <= MaxClients; i++)
710 {
711 if (IsClientInGame(i) && !IsFakeClient(i))
712 {
713 switch (type)
714 {
715 case TYPE_UNMUTE:
716 {
717 if (g_MuteType[i] > bNot)
718 {
719 iClients++;
720 strcopy(Title, sizeof(Title), g_sName[i]);
721 Format(Option, sizeof(Option), "%d %d", GetClientUserId(i), type);
722 AddMenuItem(hMenu, Option, Title, (CanUserTarget(client, i) ? ITEMDRAW_DEFAULT : ITEMDRAW_DISABLED));
723 }
724 }
725 case TYPE_UNGAG:
726 {
727 if (g_GagType[i] > bNot)
728 {
729 iClients++;
730 strcopy(Title, sizeof(Title), g_sName[i]);
731 Format(Option, sizeof(Option), "%d %d", GetClientUserId(i), type);
732 AddMenuItem(hMenu, Option, Title, (CanUserTarget(client, i) ? ITEMDRAW_DEFAULT : ITEMDRAW_DISABLED));
733 }
734 }
735 case TYPE_UNSILENCE:
736 {
737 if (g_MuteType[i] > bNot && g_GagType[i] > bNot)
738 {
739 iClients++;
740 strcopy(Title, sizeof(Title), g_sName[i]);
741 Format(Option, sizeof(Option), "%d %d", GetClientUserId(i), type);
742 AddMenuItem(hMenu, Option, Title, (CanUserTarget(client, i) ? ITEMDRAW_DEFAULT : ITEMDRAW_DISABLED));
743 }
744 }
745 }
746 }
747 }
748 }
749 if (!iClients)
750 {
751 switch (type)
752 {
753 case TYPE_UNMUTE:
754 Format(Title, sizeof(Title), "%T", "AdminMenu_Option_Mute_Empty", client);
755 case TYPE_UNGAG:
756 Format(Title, sizeof(Title), "%T", "AdminMenu_Option_Gag_Empty", client);
757 case TYPE_UNSILENCE:
758 Format(Title, sizeof(Title), "%T", "AdminMenu_Option_Silence_Empty", client);
759 default:
760 Format(Title, sizeof(Title), "%T", "AdminMenu_Option_Empty", client);
761 }
762 AddMenuItem(hMenu, "0", Title, ITEMDRAW_DISABLED);
763 }
764
765 DisplayMenu(hMenu, client, MENU_TIME_FOREVER);
766}
767
768public MenuHandler_MenuTarget(Handle:menu, MenuAction:action, param1, param2)
769{
770 switch (action)
771 {
772 case MenuAction_End:
773 CloseHandle(menu);
774 case MenuAction_Cancel:
775 {
776 if (param2 == MenuCancel_ExitBack && hTopMenu != INVALID_HANDLE)
777 DisplayTopMenu(hTopMenu, param1, TopMenuPosition_LastCategory);
778 }
779 case MenuAction_Select:
780 {
781 decl String:Option[32], String:Temp[2][8];
782 GetMenuItem(menu, param2, Option, sizeof(Option));
783 ExplodeString(Option, " ", Temp, 2, 8);
784 new target = GetClientOfUserId(StringToInt(Temp[0]));
785
786 if (Bool_ValidMenuTarget(param1, target))
787 {
788 new type = StringToInt(Temp[1]);
789 if (type <= TYPE_SILENCE)
790 AdminMenu_Duration(param1, target, type);
791 else
792 ProcessUnBlock(param1, target, type);
793 }
794 }
795 }
796}
797
798AdminMenu_Duration(client, target, type)
799{
800 new Handle:hMenu = CreateMenu(MenuHandler_MenuDuration);
801 decl String:sBuffer[192], String:sTemp[64];
802 Format(sBuffer, sizeof(sBuffer), "%T", "AdminMenu_Title_Durations", client);
803 SetMenuTitle(hMenu, sBuffer);
804 SetMenuExitBackButton(hMenu, true);
805
806 for (new i = 0; i <= iNumTimes; i++)
807 {
808 if (IsAllowedBlockLength(client, g_iTimeMinutes[i]))
809 {
810 Format(sTemp, sizeof(sTemp), "%d %d %d", GetClientUserId(target), type, i); // TargetID TYPE_BLOCK index_of_Time
811 AddMenuItem(hMenu, sTemp, g_sTimeDisplays[i]);
812 }
813 }
814
815 DisplayMenu(hMenu, client, MENU_TIME_FOREVER);
816}
817
818public MenuHandler_MenuDuration(Handle:menu, MenuAction:action, param1, param2)
819{
820 switch (action)
821 {
822 case MenuAction_End:
823 CloseHandle(menu);
824 case MenuAction_Cancel:
825 {
826 if (param2 == MenuCancel_ExitBack && hTopMenu != INVALID_HANDLE)
827 DisplayTopMenu(hTopMenu, param1, TopMenuPosition_LastCategory);
828 }
829 case MenuAction_Select:
830 {
831 decl String:sOption[32], String:sTemp[3][8];
832 GetMenuItem(menu, param2, sOption, sizeof(sOption));
833 ExplodeString(sOption, " ", sTemp, 3, 8);
834 // TargetID TYPE_BLOCK index_of_Time
835 new target = GetClientOfUserId(StringToInt(sTemp[0]));
836
837 if (Bool_ValidMenuTarget(param1, target))
838 {
839 new type = StringToInt(sTemp[1]);
840 new lengthIndex = StringToInt(sTemp[2]);
841
842 if (iNumReasons) // we have reasons to show
843 AdminMenu_Reason(param1, target, type, lengthIndex);
844 else
845 CreateBlock(param1, target, g_iTimeMinutes[lengthIndex], type);
846 }
847 }
848 }
849}
850
851AdminMenu_Reason(client, target, type, lengthIndex)
852{
853 new Handle:hMenu = CreateMenu(MenuHandler_MenuReason);
854 decl String:sBuffer[192], String:sTemp[64];
855 Format(sBuffer, sizeof(sBuffer), "%T", "AdminMenu_Title_Reasons", client);
856 SetMenuTitle(hMenu, sBuffer);
857 SetMenuExitBackButton(hMenu, true);
858
859 for (new i = 0; i <= iNumReasons; i++)
860 {
861 Format(sTemp, sizeof(sTemp), "%d %d %d %d", GetClientUserId(target), type, i, lengthIndex); // TargetID TYPE_BLOCK ReasonIndex LenghtIndex
862 AddMenuItem(hMenu, sTemp, g_sReasonDisplays[i]);
863 }
864
865 DisplayMenu(hMenu, client, MENU_TIME_FOREVER);
866}
867
868public MenuHandler_MenuReason(Handle:menu, MenuAction:action, param1, param2)
869{
870 switch (action)
871 {
872 case MenuAction_End:
873 CloseHandle(menu);
874 case MenuAction_Cancel:
875 {
876 if (param2 == MenuCancel_ExitBack && hTopMenu != INVALID_HANDLE)
877 DisplayTopMenu(hTopMenu, param1, TopMenuPosition_LastCategory);
878 }
879 case MenuAction_Select:
880 {
881 decl String:sOption[64], String:sTemp[4][8];
882 GetMenuItem(menu, param2, sOption, sizeof(sOption));
883 ExplodeString(sOption, " ", sTemp, 4, 8);
884 // TargetID TYPE_BLOCK ReasonIndex LenghtIndex
885 new target = GetClientOfUserId(StringToInt(sTemp[0]));
886
887 if (Bool_ValidMenuTarget(param1, target))
888 {
889 new type = StringToInt(sTemp[1]);
890 new reasonIndex = StringToInt(sTemp[2]);
891 new lengthIndex = StringToInt(sTemp[3]);
892 new length;
893 if (lengthIndex >= 0 && lengthIndex <= iNumTimes)
894 length = g_iTimeMinutes[lengthIndex];
895 else
896 {
897 length = DefaultTime;
898 LogError("Wrong length index in menu - using default time");
899 }
900
901 CreateBlock(param1, target, length, type, g_sReasonKey[reasonIndex]);
902 }
903 }
904 }
905}
906
907AdminMenu_List(client, index)
908{
909 decl String:sTitle[192], String:sOption[32];
910 Format(sTitle, sizeof(sTitle), "%T", "AdminMenu_Select_List", client);
911 new iClients, Handle:hMenu = CreateMenu(MenuHandler_MenuList);
912 SetMenuTitle(hMenu, sTitle);
913 if (!g_iPeskyPanels[client][viewingList])
914 SetMenuExitBackButton(hMenu, true);
915
916 for (new i = 1; i <= MaxClients; i++)
917 {
918 if (IsClientInGame(i) && !IsFakeClient(i) && (g_MuteType[i] > bNot || g_GagType[i] > bNot))
919 {
920 iClients++;
921 strcopy(sTitle, sizeof(sTitle), g_sName[i]);
922 AdminMenu_GetPunishPhrase(client, i, sTitle, sizeof(sTitle));
923 Format(sOption, sizeof(sOption), "%d", GetClientUserId(i));
924 AddMenuItem(hMenu, sOption, sTitle);
925 }
926 }
927
928 if (!iClients)
929 {
930 Format(sTitle, sizeof(sTitle), "%T", "ListMenu_Option_Empty", client);
931 AddMenuItem(hMenu, "0", sTitle, ITEMDRAW_DISABLED);
932 }
933
934 DisplayMenuAtItem(hMenu, client, index, MENU_TIME_FOREVER);
935}
936
937public MenuHandler_MenuList(Handle:menu, MenuAction:action, param1, param2)
938{
939 switch (action)
940 {
941 case MenuAction_End:
942 CloseHandle(menu);
943 case MenuAction_Cancel:
944 {
945 if (!g_iPeskyPanels[param1][viewingList])
946 if (param2 == MenuCancel_ExitBack && hTopMenu != INVALID_HANDLE)
947 DisplayTopMenu(hTopMenu, param1, TopMenuPosition_LastCategory);
948 }
949 case MenuAction_Select:
950 {
951 decl String:sOption[32];
952 GetMenuItem(menu, param2, sOption, sizeof(sOption));
953 new target = GetClientOfUserId(StringToInt(sOption));
954
955 if (Bool_ValidMenuTarget(param1, target))
956 AdminMenu_ListTarget(param1, target, GetMenuSelectionPosition());
957 else
958 AdminMenu_List(param1, GetMenuSelectionPosition());
959 }
960 }
961}
962
963AdminMenu_ListTarget(client, target, index, viewMute = 0, viewGag = 0)
964{
965 new userid = GetClientUserId(target), Handle:hMenu = CreateMenu(MenuHandler_MenuListTarget);
966 decl String:sBuffer[192], String:sOption[32];
967 SetMenuTitle(hMenu, g_sName[target]);
968 SetMenuPagination(hMenu, MENU_NO_PAGINATION);
969 SetMenuExitButton(hMenu, true);
970 SetMenuExitBackButton(hMenu, false);
971
972 if (g_MuteType[target] > bNot)
973 {
974 Format(sBuffer, sizeof(sBuffer), "%T", "ListMenu_Option_Mute", client);
975 Format(sOption, sizeof(sOption), "0 %d %d %b %b", userid, index, viewMute, viewGag);
976 AddMenuItem(hMenu, sOption, sBuffer);
977
978 if (viewMute)
979 {
980 Format(sBuffer, sizeof(sBuffer), "%T", "ListMenu_Option_Admin", client, g_sMuteAdminName[target]);
981 AddMenuItem(hMenu, "", sBuffer, ITEMDRAW_DISABLED);
982
983 decl String:sMuteTemp[192], String:_sMuteTime[192];
984 Format(sMuteTemp, sizeof(sMuteTemp), "%T", "ListMenu_Option_Duration", client);
985 switch (g_MuteType[target])
986 {
987 case bPerm:Format(sBuffer, sizeof(sBuffer), "%s%T", sMuteTemp, "ListMenu_Option_Duration_Perm", client);
988 case bTime:Format(sBuffer, sizeof(sBuffer), "%s%T", sMuteTemp, "ListMenu_Option_Duration_Time", client, g_iMuteLength[target]);
989 case bSess:Format(sBuffer, sizeof(sBuffer), "%s%T", sMuteTemp, "ListMenu_Option_Duration_Temp", client);
990 default:Format(sBuffer, sizeof(sBuffer), "error");
991 }
992 AddMenuItem(hMenu, "", sBuffer, ITEMDRAW_DISABLED);
993
994 FormatTime(_sMuteTime, sizeof(_sMuteTime), NULL_STRING, g_iMuteTime[target]);
995 Format(sBuffer, sizeof(sBuffer), "%T", "ListMenu_Option_Issue", client, _sMuteTime);
996 AddMenuItem(hMenu, "", sBuffer, ITEMDRAW_DISABLED);
997
998 Format(sMuteTemp, sizeof(sMuteTemp), "%T", "ListMenu_Option_Expire", client);
999 switch (g_MuteType[target])
1000 {
1001 case bTime:
1002 {
1003 FormatTime(_sMuteTime, sizeof(_sMuteTime), NULL_STRING, (g_iMuteTime[target] + g_iMuteLength[target] * 60));
1004 Format(sBuffer, sizeof(sBuffer), "%s%T", sMuteTemp, "ListMenu_Option_Expire_Time", client, _sMuteTime);
1005 }
1006 case bPerm:Format(sBuffer, sizeof(sBuffer), "%s%T", sMuteTemp, "ListMenu_Option_Expire_Perm", client);
1007 case bSess:Format(sBuffer, sizeof(sBuffer), "%s%T", sMuteTemp, "ListMenu_Option_Expire_Temp_Reconnect", client);
1008 default:Format(sBuffer, sizeof(sBuffer), "error");
1009 }
1010 AddMenuItem(hMenu, "", sBuffer, ITEMDRAW_DISABLED);
1011
1012 if (strlen(g_sMuteReason[target]) > 0)
1013 {
1014 Format(sBuffer, sizeof(sBuffer), "%T", "ListMenu_Option_Reason", client);
1015 Format(sOption, sizeof(sOption), "1 %d %d %b %b", userid, index, viewMute, viewGag);
1016 AddMenuItem(hMenu, sOption, sBuffer);
1017 }
1018 else
1019 {
1020 Format(sBuffer, sizeof(sBuffer), "%T", "ListMenu_Option_Reason_None", client);
1021 AddMenuItem(hMenu, "", sBuffer, ITEMDRAW_DISABLED);
1022 }
1023 }
1024 }
1025
1026 if (g_GagType[target] > bNot)
1027 {
1028 Format(sBuffer, sizeof(sBuffer), "%T", "ListMenu_Option_Gag", client);
1029 Format(sOption, sizeof(sOption), "2 %d %d %b %b", userid, index, viewMute, viewGag);
1030 AddMenuItem(hMenu, sOption, sBuffer);
1031
1032 if (viewGag)
1033 {
1034 Format(sBuffer, sizeof(sBuffer), "%T", "ListMenu_Option_Admin", client, g_sGagAdminName[target]);
1035 AddMenuItem(hMenu, "", sBuffer, ITEMDRAW_DISABLED);
1036
1037 decl String:sGagTemp[192], String:_sGagTime[192];
1038 Format(sGagTemp, sizeof(sGagTemp), "%T", "ListMenu_Option_Duration", client);
1039
1040 switch (g_GagType[target])
1041 {
1042 case bPerm:Format(sBuffer, sizeof(sBuffer), "%s%T", sGagTemp, "ListMenu_Option_Duration_Perm", client);
1043 case bTime:Format(sBuffer, sizeof(sBuffer), "%s%T", sGagTemp, "ListMenu_Option_Duration_Time", client, g_iGagLength[target]);
1044 case bSess:Format(sBuffer, sizeof(sBuffer), "%s%T", sGagTemp, "ListMenu_Option_Duration_Temp", client);
1045 default:Format(sBuffer, sizeof(sBuffer), "error");
1046 }
1047
1048 AddMenuItem(hMenu, "", sBuffer, ITEMDRAW_DISABLED);
1049
1050 FormatTime(_sGagTime, sizeof(_sGagTime), NULL_STRING, g_iGagTime[target]);
1051 Format(sBuffer, sizeof(sBuffer), "%T", "ListMenu_Option_Issue", client, _sGagTime);
1052 AddMenuItem(hMenu, "", sBuffer, ITEMDRAW_DISABLED);
1053
1054 Format(sGagTemp, sizeof(sGagTemp), "%T", "ListMenu_Option_Expire", client);
1055
1056 switch (g_GagType[target])
1057 {
1058 case bTime:
1059 {
1060 FormatTime(_sGagTime, sizeof(_sGagTime), NULL_STRING, (g_iGagTime[target] + g_iGagLength[target] * 60));
1061 Format(sBuffer, sizeof(sBuffer), "%s%T", sGagTemp, "ListMenu_Option_Expire_Time", client, _sGagTime);
1062 }
1063 case bPerm:Format(sBuffer, sizeof(sBuffer), "%s%T", sGagTemp, "ListMenu_Option_Expire_Perm", client);
1064 case bSess:Format(sBuffer, sizeof(sBuffer), "%s%T", sGagTemp, "ListMenu_Option_Expire_Temp_Reconnect", client);
1065 default:Format(sBuffer, sizeof(sBuffer), "error");
1066 }
1067
1068 AddMenuItem(hMenu, "", sBuffer, ITEMDRAW_DISABLED);
1069
1070 if (strlen(g_sGagReason[target]) > 0)
1071 {
1072 Format(sBuffer, sizeof(sBuffer), "%T", "ListMenu_Option_Reason", client);
1073 Format(sOption, sizeof(sOption), "3 %d %d %b %b", userid, index, viewMute, viewGag);
1074 AddMenuItem(hMenu, sOption, sBuffer);
1075 }
1076 else
1077 {
1078 Format(sBuffer, sizeof(sBuffer), "%T", "ListMenu_Option_Reason_None", client);
1079 AddMenuItem(hMenu, "", sBuffer, ITEMDRAW_DISABLED);
1080 }
1081 }
1082 }
1083
1084 g_iPeskyPanels[client][curIndex] = index;
1085 g_iPeskyPanels[client][curTarget] = target;
1086 g_iPeskyPanels[client][viewingGag] = viewGag;
1087 g_iPeskyPanels[client][viewingMute] = viewMute;
1088 DisplayMenu(hMenu, client, MENU_TIME_FOREVER);
1089}
1090
1091public MenuHandler_MenuListTarget(Handle:menu, MenuAction:action, param1, param2)
1092{
1093 switch (action)
1094 {
1095 case MenuAction_End:
1096 CloseHandle(menu);
1097 case MenuAction_Cancel:
1098 {
1099 if (param2 == MenuCancel_ExitBack)
1100 AdminMenu_List(param1, g_iPeskyPanels[param1][curIndex]);
1101 }
1102 case MenuAction_Select:
1103 {
1104 decl String:sOption[64], String:sTemp[5][8];
1105 GetMenuItem(menu, param2, sOption, sizeof(sOption));
1106 ExplodeString(sOption, " ", sTemp, 5, 8);
1107
1108 new target = GetClientOfUserId(StringToInt(sTemp[1]));
1109 if (param1 == target || Bool_ValidMenuTarget(param1, target))
1110 {
1111 switch (StringToInt(sTemp[0]))
1112 {
1113 case 0:
1114 AdminMenu_ListTarget(param1, target, StringToInt(sTemp[2]), !(StringToInt(sTemp[3])), 0);
1115 case 1, 3:
1116 AdminMenu_ListTargetReason(param1, target, g_iPeskyPanels[param1][viewingMute], g_iPeskyPanels[param1][viewingGag]);
1117 case 2:
1118 AdminMenu_ListTarget(param1, target, StringToInt(sTemp[2]), 0, !(StringToInt(sTemp[4])));
1119 }
1120 }
1121 else
1122 AdminMenu_List(param1, StringToInt(sTemp[2]));
1123
1124 }
1125 }
1126}
1127
1128AdminMenu_ListTargetReason(client, target, showMute, showGag)
1129{
1130 decl String:sTemp[192], String:sBuffer[192];
1131 new Handle:hPanel = CreatePanel();
1132 SetPanelTitle(hPanel, g_sName[target]);
1133 DrawPanelItem(hPanel, " ", ITEMDRAW_SPACER | ITEMDRAW_RAWLINE);
1134
1135 if (showMute)
1136 {
1137 Format(sTemp, sizeof(sTemp), "%T", "ReasonPanel_Punishment_Mute", client);
1138 switch (g_MuteType[target])
1139 {
1140 case bPerm:Format(sBuffer, sizeof(sBuffer), "%s%T", sTemp, "ReasonPanel_Perm", client);
1141 case bTime:Format(sBuffer, sizeof(sBuffer), "%s%T", sTemp, "ReasonPanel_Time", client, g_iMuteLength[target]);
1142 case bSess:Format(sBuffer, sizeof(sBuffer), "%s%T", sTemp, "ReasonPanel_Temp", client);
1143 default:Format(sBuffer, sizeof(sBuffer), "error");
1144 }
1145 DrawPanelText(hPanel, sBuffer);
1146
1147 Format(sBuffer, sizeof(sBuffer), "%T", "ReasonPanel_Reason", client, g_sMuteReason[target]);
1148 DrawPanelText(hPanel, sBuffer);
1149 }
1150 else if (showGag)
1151 {
1152 Format(sTemp, sizeof(sTemp), "%T", "ReasonPanel_Punishment_Gag", client);
1153 switch (g_GagType[target])
1154 {
1155 case bPerm:Format(sBuffer, sizeof(sBuffer), "%s%T", sTemp, "ReasonPanel_Perm", client);
1156 case bTime:Format(sBuffer, sizeof(sBuffer), "%s%T", sTemp, "ReasonPanel_Time", client, g_iGagLength[target]);
1157 case bSess:Format(sBuffer, sizeof(sBuffer), "%s%T", sTemp, "ReasonPanel_Temp", client);
1158 default:Format(sBuffer, sizeof(sBuffer), "error");
1159 }
1160 DrawPanelText(hPanel, sBuffer);
1161
1162 Format(sBuffer, sizeof(sBuffer), "%T", "ReasonPanel_Reason", client, g_sGagReason[target]);
1163 DrawPanelText(hPanel, sBuffer);
1164 }
1165
1166 DrawPanelItem(hPanel, " ", ITEMDRAW_SPACER | ITEMDRAW_RAWLINE);
1167 SetPanelCurrentKey(hPanel, 10);
1168 Format(sBuffer, sizeof(sBuffer), "%T", "ReasonPanel_Back", client);
1169 DrawPanelItem(hPanel, sBuffer);
1170 SendPanelToClient(hPanel, client, PanelHandler_ListTargetReason, MENU_TIME_FOREVER);
1171 CloseHandle(hPanel);
1172}
1173
1174public PanelHandler_ListTargetReason(Handle:menu, MenuAction:action, param1, param2)
1175{
1176 if (action == MenuAction_Select)
1177 {
1178 AdminMenu_ListTarget(param1, g_iPeskyPanels[param1][curTarget],
1179 g_iPeskyPanels[param1][curIndex],
1180 g_iPeskyPanels[param1][viewingMute],
1181 g_iPeskyPanels[param1][viewingGag]);
1182 }
1183}
1184
1185
1186// SQL CALLBACKS //
1187
1188public GotDatabase(Handle:owner, Handle:hndl, const String:error[], any:data)
1189{
1190 #if defined DEBUG
1191 PrintToServer("GotDatabase(data: %d, lock: %d, g_h: %d, hndl: %d)", data, g_iConnectLock, g_hDatabase, hndl);
1192 #endif
1193
1194 // If this happens to be an old connection request, ignore it.
1195 if (data != g_iConnectLock || g_hDatabase)
1196 {
1197 if (hndl)
1198 CloseHandle(hndl);
1199 return;
1200 }
1201
1202 g_iConnectLock = 0;
1203 g_DatabaseState = DatabaseState_Connected;
1204 g_hDatabase = hndl;
1205
1206 // See if the connection is valid. If not, don't un-mark the caches
1207 // as needing rebuilding, in case the next connection request works.
1208 if (!g_hDatabase)
1209 {
1210 LogError("Connecting to database failed: %s", error);
1211 return;
1212 }
1213
1214 // Set character set to UTF-8 in the database
1215 if (GetFeatureStatus(FeatureType_Native, "SQL_SetCharset") == FeatureStatus_Available)
1216 {
1217 SQL_SetCharset(g_hDatabase, "utf8");
1218 }
1219 else
1220 {
1221 decl String:query[128];
1222 FormatEx(query, sizeof(query), "SET NAMES 'UTF8'");
1223 #if defined LOG_QUERIES
1224 LogToFile(logQuery, "Set encoding. QUERY: %s", query);
1225 #endif
1226 SQL_TQuery(g_hDatabase, Query_ErrorCheck, query);
1227 }
1228
1229 // Process queue
1230 SQL_TQuery(SQLiteDB, Query_ProcessQueue,
1231 "SELECT id, steam_id, time, start_time, reason, name, admin_id, admin_ip, type \
1232 FROM queue2");
1233
1234 // Force recheck players
1235 ForcePlayersRecheck();
1236}
1237
1238public Query_AddBlockInsert(Handle:owner, Handle:hndl, const String:error[], any:data)
1239{
1240 ResetPack(data);
1241
1242 decl String:reason[256];
1243
1244 new iAdminUserId = ReadPackCell(data);
1245 new iAdmin = 0;
1246
1247 if(iAdminUserId > 0) {
1248 iAdmin = GetClientOfUserId(iAdminUserId);
1249 }
1250
1251 new iTarget = GetClientOfUserId(ReadPackCell(data));
1252
1253 if (!iTarget) {
1254 iTarget = -1;
1255 }
1256
1257 new length = ReadPackCell(data);
1258 new type = ReadPackCell(data);
1259 ReadPackString(data, reason, sizeof(reason));
1260
1261 // Fire forward
1262 Call_StartForward(g_hFwd_OnPlayerPunished);
1263 Call_PushCell(iAdmin);
1264 Call_PushCell(iTarget);
1265 Call_PushCell(length);
1266 Call_PushCell(type);
1267 Call_PushString(reason);
1268 Call_Finish();
1269
1270 if (DB_Conn_Lost(hndl) || error[0])
1271 {
1272 LogError("Query_AddBlockInsert failed: %s", error);
1273
1274 decl String:name[MAX_NAME_LENGTH], String:auth[64], String:adminAuth[32], String:adminIp[20];
1275 ReadPackString(data, name, sizeof(name));
1276 ReadPackString(data, auth, sizeof(auth));
1277 ReadPackString(data, adminAuth, sizeof(adminAuth));
1278 ReadPackString(data, adminIp, sizeof(adminIp));
1279
1280 InsertTempBlock(length, type, name, auth, reason, adminAuth, adminIp);
1281 }
1282 CloseHandle(data);
1283}
1284
1285public Query_UnBlockSelect(Handle:owner, Handle:hndl, const String:error[], any:data)
1286{
1287 decl String:adminAuth[30], String:targetAuth[30];
1288 new String:reason[256];
1289
1290 ResetPack(data);
1291 new adminUserID = ReadPackCell(data);
1292 new targetUserID = ReadPackCell(data);
1293 new type = ReadPackCell(data); // not in use unless DEBUG
1294 ReadPackString(data, adminAuth, sizeof(adminAuth));
1295 ReadPackString(data, targetAuth, sizeof(targetAuth));
1296 ReadPackString(data, reason, sizeof(reason));
1297
1298 new admin = GetClientOfUserId(adminUserID);
1299 new target = GetClientOfUserId(targetUserID);
1300
1301 #if defined DEBUG
1302 PrintToServer("Query_UnBlockSelect(adminUID: %d/%d, targetUID: %d/%d, type: %d, adminAuth: %s, targetAuth: %s, reason: %s)",
1303 adminUserID, admin, targetUserID, target, type, adminAuth, targetAuth, reason);
1304 #endif
1305
1306 decl String:targetName[MAX_NAME_LENGTH];
1307 strcopy(targetName, MAX_NAME_LENGTH, target && IsClientInGame(target) ? g_sName[target] : targetAuth); //FIXME
1308
1309 new bool:hasErrors = false;
1310 // If error is not an empty string the query failed
1311 if (DB_Conn_Lost(hndl) || error[0] != '\0')
1312 {
1313 LogError("Query_UnBlockSelect failed: %s", error);
1314 if (admin && IsClientInGame(admin))
1315 {
1316 PrintToChat(admin, "%s%T", PREFIX, "Unblock Select Failed", admin, targetAuth);
1317 PrintToConsole(admin, "%s%T", PREFIX, "Unblock Select Failed", admin, targetAuth);
1318 }
1319 else
1320 {
1321 PrintToServer("%s%T", PREFIX, "Unblock Select Failed", LANG_SERVER, targetAuth);
1322 }
1323 hasErrors = true;
1324 }
1325
1326 // If there was no results then a ban does not exist for that id
1327 if (!DB_Conn_Lost(hndl) && !SQL_GetRowCount(hndl))
1328 {
1329 if (admin && IsClientInGame(admin))
1330 {
1331 PrintToChat(admin, "%s%t", PREFIX, "No blocks found", targetAuth);
1332 PrintToConsole(admin, "%s%t", PREFIX, "No blocks found", targetAuth);
1333 }
1334 else
1335 {
1336 PrintToServer("%s%T", PREFIX, "No blocks found", LANG_SERVER, targetAuth);
1337 }
1338 hasErrors = true;
1339 }
1340
1341 if (hasErrors)
1342 {
1343 #if defined DEBUG
1344 PrintToServer("Calling TempUnBlock from Query_UnBlockSelect");
1345 #endif
1346
1347 TempUnBlock(data); // Datapack closed inside.
1348 return;
1349 }
1350 else
1351 {
1352 new bool:b_success = false;
1353 // Get the values from the founded blocks.
1354 while (SQL_MoreRows(hndl))
1355 {
1356 // Oh noes! What happened?!
1357 if (!SQL_FetchRow(hndl))
1358 continue;
1359
1360 new bid = SQL_FetchInt(hndl, 0);
1361 new iAID = SQL_FetchInt(hndl, 1);
1362 new cAID = SQL_FetchInt(hndl, 2);
1363 new cImmunity = SQL_FetchInt(hndl, 3);
1364 new cType = SQL_FetchInt(hndl, 4);
1365
1366 #if defined DEBUG
1367 PrintToServer("Fetched from DB: bid %d, iAID: %d, cAID: %d, cImmunity: %d, cType: %d", bid, iAID, cAID, cImmunity, cType);
1368 // WHO WE ARE?
1369 PrintToServer("WHO WE ARE CHECKING!");
1370 if (iAID == cAID)
1371 PrintToServer("we are block author");
1372 if (!admin)
1373 PrintToServer("we are console (possibly)");
1374 if (AdmHasFlag(admin))
1375 PrintToServer("we have special flag");
1376 if (GetAdmImmunity(admin) > cImmunity)
1377 PrintToServer("we have %d immunity and block has %d. we cool", GetAdmImmunity(admin), cImmunity);
1378 #endif
1379
1380 // Checking - has we access to unblock?
1381 if (iAID == cAID || (!admin && StrEqual(adminAuth, "STEAM_ID_SERVER")) || AdmHasFlag(admin) || (DisUBImCheck == 0 && (GetAdmImmunity(admin) > cImmunity)))
1382 {
1383 // Ok! we have rights to unblock
1384 b_success = true;
1385 // UnMute/UnGag, Show & log activity
1386 if (target && IsClientInGame(target))
1387 {
1388 switch (cType)
1389 {
1390 case TYPE_MUTE:
1391 {
1392 PerformUnMute(target);
1393 LogAction(admin, target, "\"%L\" unmuted \"%L\" (reason \"%s\")", admin, target, reason);
1394 }
1395 //-------------------------------------------------------------------------------------------------
1396 case TYPE_GAG:
1397 {
1398 PerformUnGag(target);
1399 LogAction(admin, target, "\"%L\" ungagged \"%L\" (reason \"%s\")", admin, target, reason);
1400 }
1401 }
1402 }
1403
1404 new Handle:dataPack = CreateDataPack();
1405 WritePackCell(dataPack, adminUserID);
1406 WritePackCell(dataPack, cType);
1407 WritePackString(dataPack, g_sName[target]);
1408 WritePackString(dataPack, targetAuth);
1409
1410 decl String:unbanReason[sizeof(reason) * 2 + 1];
1411 SQL_EscapeString(g_hDatabase, reason, unbanReason, sizeof(unbanReason));
1412
1413 decl String:query[2048];
1414 Format(query, sizeof(query),
1415 "UPDATE %s_comms \
1416 SET RemovedBy = %d, \
1417 RemoveType = 'U', \
1418 RemovedOn = UNIX_TIMESTAMP(), \
1419 ureason = '%s' \
1420 WHERE bid = %d",
1421 DatabasePrefix, iAID, unbanReason, bid);
1422 #if defined LOG_QUERIES
1423 LogToFile(logQuery, "Query_UnBlockSelect. QUERY: %s", query);
1424 #endif
1425 SQL_TQuery(g_hDatabase, Query_UnBlockUpdate, query, dataPack);
1426 }
1427 else
1428 {
1429 // sorry, we don't have permission to unblock!
1430 #if defined DEBUG
1431 PrintToServer("No permissions to unblock in Query_UnBlockSelect");
1432 #endif
1433 switch (cType)
1434 {
1435 case TYPE_MUTE:
1436 {
1437 if (admin && IsClientInGame(admin))
1438 {
1439 PrintToChat(admin, "%s%t", PREFIX, "No permission unmute", targetName);
1440 PrintToConsole(admin, "%s%t", PREFIX, "No permission unmute", targetName);
1441 }
1442 LogAction(admin, target, "\"%L\" tried (and didn't have permission) to unmute %s (reason \"%s\")", admin, targetAuth, reason);
1443 }
1444 //-------------------------------------------------------------------------------------------------
1445 case TYPE_GAG:
1446 {
1447 if (admin && IsClientInGame(admin))
1448 {
1449 PrintToChat(admin, "%s%t", PREFIX, "No permission ungag", targetName);
1450 PrintToConsole(admin, "%s%t", PREFIX, "No permission ungag", targetName);
1451 }
1452 LogAction(admin, target, "\"%L\" tried (and didn't have permission) to ungag %s (reason \"%s\")", admin, targetAuth, reason);
1453 }
1454 }
1455 }
1456 }
1457
1458 if (b_success && target && IsClientInGame(target))
1459 {
1460 #if defined DEBUG
1461 PrintToServer("Showing activity to server in Query_UnBlockSelect");
1462 #endif
1463 ShowActivityToServer(admin, type, _, _, g_sName[target], _);
1464
1465 if (type == TYPE_UNSILENCE)
1466 {
1467 // check result for possible combination with temp and time punishments (temp was skipped in code above)
1468
1469 #if SOURCEMOD_V_MAJOR >= 1 && SOURCEMOD_V_MINOR >= 8
1470 SetPackPosition(data, view_as<DataPackPos>(16));
1471 #else
1472 SetPackPosition(data, 16);
1473 #endif
1474
1475 if (g_MuteType[target] > bNot)
1476 {
1477 WritePackCell(data, TYPE_UNMUTE);
1478 TempUnBlock(data);
1479 data = INVALID_HANDLE;
1480 }
1481 else if (g_GagType[target] > bNot)
1482 {
1483 WritePackCell(data, TYPE_UNGAG);
1484 TempUnBlock(data);
1485 data = INVALID_HANDLE;
1486 }
1487 }
1488 }
1489 }
1490 if (data != INVALID_HANDLE)
1491 CloseHandle(data);
1492}
1493
1494public Query_UnBlockUpdate(Handle:owner, Handle:hndl, const String:error[], any:data)
1495{
1496 new admin, type;
1497 decl String:targetName[MAX_NAME_LENGTH], String:targetAuth[30];
1498
1499 ResetPack(data);
1500 admin = GetClientOfUserId(ReadPackCell(data));
1501 type = ReadPackCell(data);
1502 ReadPackString(data, targetName, sizeof(targetName));
1503 ReadPackString(data, targetAuth, sizeof(targetAuth));
1504 CloseHandle(data);
1505
1506 if (DB_Conn_Lost(hndl) || error[0] != '\0')
1507 {
1508 LogError("Query_UnBlockUpdate failed: %s", error);
1509 if (admin && IsClientInGame(admin))
1510 {
1511 PrintToChat(admin, "%s%t", PREFIX, "Unblock insert failed");
1512 PrintToConsole(admin, "%s%t", PREFIX, "Unblock insert failed");
1513 }
1514 return;
1515 }
1516
1517 switch (type)
1518 {
1519 case TYPE_MUTE:
1520 {
1521 LogAction(admin, -1, "\"%L\" removed mute for %s from DB", admin, targetAuth);
1522 if (admin && IsClientInGame(admin))
1523 {
1524 PrintToChat(admin, "%s%t", PREFIX, "successfully unmuted", targetName);
1525 PrintToConsole(admin, "%s%t", PREFIX, "successfully unmuted", targetName);
1526 }
1527 else
1528 {
1529 PrintToServer("%s%T", PREFIX, "successfully unmuted", LANG_SERVER, targetName);
1530 }
1531 }
1532 //-------------------------------------------------------------------------------------------------
1533 case TYPE_GAG:
1534 {
1535 LogAction(admin, -1, "\"%L\" removed gag for %s from DB", admin, targetAuth);
1536 if (admin && IsClientInGame(admin)) {
1537 PrintToChat(admin, "%s%t", PREFIX, "successfully ungagged", targetName);
1538 PrintToConsole(admin, "%s%t", PREFIX, "successfully ungagged", targetName);
1539 }
1540 else
1541 {
1542 PrintToServer("%s%T", PREFIX, "successfully ungagged", LANG_SERVER, targetName);
1543 }
1544 }
1545 }
1546}
1547
1548// ProcessQueueCallback is called as the result of selecting all the rows from the queue table
1549public Query_ProcessQueue(Handle:owner, Handle:hndl, const String:error[], any:data)
1550{
1551 if (hndl == INVALID_HANDLE || error[0])
1552 {
1553 LogError("Query_ProcessQueue failed: %s", error);
1554 return;
1555 }
1556
1557 decl String:auth[64];
1558 decl String:name[MAX_NAME_LENGTH];
1559 new String:reason[256];
1560 decl String:adminAuth[64], String:adminIp[20];
1561 decl String:query[4096];
1562
1563 while (SQL_MoreRows(hndl))
1564 {
1565 // Oh noes! What happened?!
1566 if (!SQL_FetchRow(hndl))
1567 continue;
1568
1569 decl String:sAuthEscaped[sizeof(auth) * 2 + 1];
1570 decl String:banName[MAX_NAME_LENGTH * 2 + 1];
1571 decl String:banReason[sizeof(reason) * 2 + 1];
1572 decl String:sAdmAuthEscaped[sizeof(adminAuth) * 2 + 1];
1573 decl String:sAdmAuthYZEscaped[sizeof(adminAuth) * 2 + 1];
1574
1575 // if we get to here then there are rows in the queue pending processing
1576 //steam_id TEXT, time INTEGER, start_time INTEGER, reason TEXT, name TEXT, admin_id TEXT, admin_ip TEXT, type INTEGER
1577 new id = SQL_FetchInt(hndl, 0);
1578 SQL_FetchString(hndl, 1, auth, sizeof(auth));
1579 new time = SQL_FetchInt(hndl, 2);
1580 new startTime = SQL_FetchInt(hndl, 3);
1581 SQL_FetchString(hndl, 4, reason, sizeof(reason));
1582 SQL_FetchString(hndl, 5, name, sizeof(name));
1583 SQL_FetchString(hndl, 6, adminAuth, sizeof(adminAuth));
1584 SQL_FetchString(hndl, 7, adminIp, sizeof(adminIp));
1585 new type = SQL_FetchInt(hndl, 8);
1586
1587 if (DB_Connect()) {
1588 SQL_EscapeString(g_hDatabase, auth, sAuthEscaped, sizeof(sAuthEscaped));
1589 SQL_EscapeString(g_hDatabase, name, banName, sizeof(banName));
1590 SQL_EscapeString(g_hDatabase, reason, banReason, sizeof(banReason));
1591 SQL_EscapeString(g_hDatabase, adminAuth, sAdmAuthEscaped, sizeof(sAdmAuthEscaped));
1592 SQL_EscapeString(g_hDatabase, adminAuth[8], sAdmAuthYZEscaped, sizeof(sAdmAuthYZEscaped));
1593 }
1594 else
1595 continue;
1596 // all blocks should be entered into db!
1597
1598 FormatEx(query, sizeof(query),
1599 "INSERT INTO %s_comms (authid, name, created, ends, length, reason, aid, adminIp, sid, type) \
1600 VALUES ('%s', '%s', %d, %d, %d, '%s', \
1601 IFNULL((SELECT aid FROM %s_admins WHERE authid = '%s' OR authid REGEXP '^STEAM_[0-9]:%s$'), '0'), \
1602 '%s', %d, %d)",
1603 DatabasePrefix, sAuthEscaped, banName, startTime, (startTime + (time * 60)), (time * 60), banReason, DatabasePrefix, sAdmAuthEscaped, sAdmAuthYZEscaped, adminIp, serverID, type);
1604 #if defined LOG_QUERIES
1605 LogToFile(logQuery, "Query_ProcessQueue. QUERY: %s", query);
1606 #endif
1607 SQL_TQuery(g_hDatabase, Query_AddBlockFromQueue, query, id);
1608 }
1609}
1610
1611public Query_AddBlockFromQueue(Handle:owner, Handle:hndl, const String:error[], any:data)
1612{
1613 decl String:query[512];
1614 if (error[0] == '\0')
1615 {
1616 // The insert was successful so delete the record from the queue
1617 FormatEx(query, sizeof(query),
1618 "DELETE FROM queue2 \
1619 WHERE id = %d",
1620 data);
1621 #if defined LOG_QUERIES
1622 LogToFile(logQuery, "Query_AddBlockFromQueue. QUERY: %s", query);
1623 #endif
1624 SQL_TQuery(SQLiteDB, Query_ErrorCheck, query);
1625 }
1626}
1627
1628public Query_ErrorCheck(Handle:owner, Handle:hndl, const String:error[], any:data)
1629{
1630 if (DB_Conn_Lost(hndl) || error[0])
1631 LogError("%T (%s)", "Failed to query database", LANG_SERVER, error);
1632}
1633
1634public Query_VerifyBlock(Handle:owner, Handle:hndl, const String:error[], any:userid)
1635{
1636 decl String:clientAuth[64];
1637 new client = GetClientOfUserId(userid);
1638
1639 #if defined DEBUG
1640 PrintToServer("Query_VerifyBlock(userid: %d, client: %d)", userid, client);
1641 #endif
1642
1643 if (!client)
1644 return;
1645
1646 /* Failure happen. Do retry with delay */
1647 if (DB_Conn_Lost(hndl))
1648 {
1649 LogError("Query_VerifyBlock failed: %s", error);
1650 if (g_hPlayerRecheck[client] == INVALID_HANDLE)
1651 g_hPlayerRecheck[client] = CreateTimer(RetryTime, ClientRecheck, userid);
1652 return;
1653 }
1654
1655 GetClientAuthId(client, AuthId_Steam2, clientAuth, sizeof(clientAuth));
1656
1657 //SELECT (c.ends - UNIX_TIMESTAMP()) as remaining, c.length, c.type, c.created, c.reason, a.user,
1658 //IF (a.immunity>=g.immunity, a.immunity, IFNULL(g.immunity,0)) as immunity, c.aid, c.sid, c.authid
1659 //FROM %s_comms c LEFT JOIN %s_admins a ON a.aid=c.aid LEFT JOIN %s_srvgroups g ON g.name = a.srv_group
1660 //WHERE c.authid REGEXP '^STEAM_[0-9]:%s$' AND (length = '0' OR ends > UNIX_TIMESTAMP()) AND RemoveType IS NULL",
1661 if (SQL_GetRowCount(hndl) > 0)
1662 {
1663 while (SQL_FetchRow(hndl))
1664 {
1665 if (NotApplyToThisServer(SQL_FetchInt(hndl, 8)))
1666 continue;
1667
1668 decl String:sAdmName[MAX_NAME_LENGTH], String:sAdmAuth[64];
1669 new String:sReason[256];
1670 new remaining_time = SQL_FetchInt(hndl, 0);
1671 new length = SQL_FetchInt(hndl, 1);
1672 new type = SQL_FetchInt(hndl, 2);
1673 new time = SQL_FetchInt(hndl, 3);
1674 SQL_FetchString(hndl, 4, sReason, sizeof(sReason));
1675 SQL_FetchString(hndl, 5, sAdmName, sizeof(sAdmName));
1676 new immunity = SQL_FetchInt(hndl, 6);
1677 new aid = SQL_FetchInt(hndl, 7);
1678 SQL_FetchString(hndl, 9, sAdmAuth, sizeof(sAdmAuth));
1679
1680 // Block from CONSOLE (aid=0) and we have `console immunity` value in config
1681 if (!aid && ConsoleImmunity > immunity)
1682 immunity = ConsoleImmunity;
1683
1684 #if defined DEBUG
1685 PrintToServer("Fetched from DB: remaining %d, length %d, type %d", remaining_time, length, type);
1686 #endif
1687
1688 switch (type)
1689 {
1690 case TYPE_MUTE:
1691 {
1692 //Set mute type based on length
1693 if (length > 0)
1694 g_MuteType[client] = bTime;
1695 else if (length == 0)
1696 g_MuteType[client] = bPerm;
1697 else
1698 g_MuteType[client] = bSess;
1699
1700 //Perform mute/unmute
1701 if (g_MuteType[client] == bSess)
1702 {
1703 PerformUnMute(client);
1704 }
1705 else if (g_MuteType[client] > bSess)
1706 {
1707 PerformMute(client, time, length / 60, sAdmName, sAdmAuth, immunity, sReason, remaining_time);
1708 PrintToChat(client, "%s%t", PREFIX, "Muted on connect");
1709 }
1710 }
1711 case TYPE_GAG:
1712 {
1713 //Set gag type based on length
1714 if (length > 0)
1715 g_GagType[client] = bTime;
1716 else if (length == 0)
1717 g_GagType[client] = bPerm;
1718 else
1719 g_GagType[client] = bSess;
1720
1721 //Perform gag/ungag
1722 if (g_GagType[client] == bSess)
1723 {
1724 PerformUnGag(client);
1725 }
1726 else if (g_GagType[client] > bSess)
1727 {
1728 PerformGag(client, time, length / 60, sAdmName, sAdmAuth, immunity, sReason, remaining_time);
1729 PrintToChat(client, "%s%t", PREFIX, "Gagged on connect");
1730 }
1731 }
1732 }
1733 }
1734 }
1735
1736 g_bPlayerStatus[client] = true;
1737}
1738
1739
1740// TIMER CALL BACKS //
1741
1742public Action:ClientRecheck(Handle:timer, any:userid)
1743{
1744 #if defined DEBUG
1745 PrintToServer("ClientRecheck(userid: %d)", userid);
1746 #endif
1747
1748 new client = GetClientOfUserId(userid);
1749 if (!client)
1750 return;
1751
1752 if (IsClientConnected(client))
1753 OnClientPostAdminCheck(client);
1754
1755 g_hPlayerRecheck[client] = INVALID_HANDLE;
1756}
1757
1758public Action:Timer_MuteExpire(Handle:timer, Handle:hPack)
1759{
1760 ResetPack(hPack);
1761 g_hMuteExpireTimer[ReadPackCell(hPack)] = INVALID_HANDLE;
1762
1763 new client = GetClientOfUserId(ReadPackCell(hPack));
1764 if (!client)
1765 return;
1766
1767 #if defined DEBUG
1768 decl String:clientAuth[64];
1769 GetClientAuthId(client, AuthId_Steam2, clientAuth, sizeof(clientAuth));
1770 PrintToServer("Mute expired for %s", clientAuth);
1771 #endif
1772
1773 PrintToChat(client, "%s%t", PREFIX, "Mute expired");
1774
1775 MarkClientAsUnMuted(client);
1776 if (IsClientInGame(client))
1777 BaseComm_SetClientMute(client, false);
1778}
1779
1780public Action:Timer_GagExpire(Handle:timer, Handle:hPack)
1781{
1782 ResetPack(hPack);
1783 g_hGagExpireTimer[ReadPackCell(hPack)] = INVALID_HANDLE;
1784
1785 new client = GetClientOfUserId(ReadPackCell(hPack));
1786 if (!client)
1787 return;
1788
1789 #if defined DEBUG
1790 decl String:clientAuth[64];
1791 GetClientAuthId(client, AuthId_Steam2, clientAuth, sizeof(clientAuth));
1792 PrintToServer("Gag expired for %s", clientAuth);
1793 #endif
1794
1795 PrintToChat(client, "%s%t", PREFIX, "Gag expired");
1796
1797 MarkClientAsUnGagged(client);
1798 if (IsClientInGame(client))
1799 BaseComm_SetClientGag(client, false);
1800}
1801
1802public Action:Timer_StopWait(Handle:timer, any:data)
1803{
1804 g_DatabaseState = DatabaseState_None;
1805 DB_Connect();
1806}
1807
1808// PARSER //
1809
1810static InitializeConfigParser()
1811{
1812 if (ConfigParser == INVALID_HANDLE)
1813 {
1814 ConfigParser = SMC_CreateParser();
1815 SMC_SetReaders(ConfigParser, ReadConfig_NewSection, ReadConfig_KeyValue, ReadConfig_EndSection);
1816 }
1817}
1818
1819static InternalReadConfig(const String:path[])
1820{
1821 ConfigState = ConfigStateNone;
1822
1823 new SMCError:err = SMC_ParseFile(ConfigParser, path);
1824
1825 if (err != SMCError_Okay)
1826 {
1827 decl String:buffer[64];
1828 PrintToServer("%s", SMC_GetErrorString(err, buffer, sizeof(buffer)) ? buffer : "Fatal parse error");
1829 }
1830}
1831
1832public SMCResult:ReadConfig_NewSection(Handle:smc, const String:name[], bool:opt_quotes)
1833{
1834 if (name[0])
1835 {
1836 if (strcmp("Config", name, false) == 0)
1837 {
1838 ConfigState = ConfigStateConfig;
1839 }
1840 else if (strcmp("CommsReasons", name, false) == 0)
1841 {
1842 ConfigState = ConfigStateReasons;
1843 }
1844 else if (strcmp("CommsTimes", name, false) == 0)
1845 {
1846 ConfigState = ConfigStateTimes;
1847 }
1848 else if (strcmp("ServersWhiteList", name, false) == 0)
1849 {
1850 ConfigState = ConfigStateServers;
1851 }
1852 }
1853 return SMCParse_Continue;
1854}
1855
1856public SMCResult:ReadConfig_KeyValue(Handle:smc, const String:key[], const String:value[], bool:key_quotes, bool:value_quotes)
1857{
1858 if (!key[0])
1859 return SMCParse_Continue;
1860
1861 switch (ConfigState)
1862 {
1863 case ConfigStateConfig:
1864 {
1865 if (strcmp("DatabasePrefix", key, false) == 0)
1866 {
1867 strcopy(DatabasePrefix, sizeof(DatabasePrefix), value);
1868
1869 if (DatabasePrefix[0] == '\0')
1870 {
1871 DatabasePrefix = "sb";
1872 }
1873 }
1874 else if (strcmp("RetryTime", key, false) == 0)
1875 {
1876 RetryTime = StringToFloat(value);
1877 if (RetryTime < 15.0)
1878 {
1879 RetryTime = 15.0;
1880 }
1881 else if (RetryTime > 60.0)
1882 {
1883 RetryTime = 60.0;
1884 }
1885 }
1886 else if (strcmp("ServerID", key, false) == 0)
1887 {
1888 if (!StringToIntEx(value, serverID) || serverID < 1)
1889 {
1890 serverID = 0;
1891 }
1892 }
1893 else if (strcmp("DefaultTime", key, false) == 0)
1894 {
1895 DefaultTime = StringToInt(value);
1896 if (DefaultTime < 0)
1897 {
1898 DefaultTime = -1;
1899 }
1900 if (DefaultTime == 0)
1901 {
1902 DefaultTime = 30;
1903 }
1904 }
1905 else if (strcmp("DisableUnblockImmunityCheck", key, false) == 0)
1906 {
1907 DisUBImCheck = StringToInt(value);
1908 if (DisUBImCheck != 1)
1909 {
1910 DisUBImCheck = 0;
1911 }
1912 }
1913 else if (strcmp("ConsoleImmunity", key, false) == 0)
1914 {
1915 ConsoleImmunity = StringToInt(value);
1916 if (ConsoleImmunity < 0 || ConsoleImmunity > 100)
1917 {
1918 ConsoleImmunity = 0;
1919 }
1920 }
1921 else if (strcmp("MaxLength", key, false) == 0)
1922 {
1923 ConfigMaxLength = StringToInt(value);
1924 }
1925 else if (strcmp("OnlyWhiteListServers", key, false) == 0)
1926 {
1927 ConfigWhiteListOnly = StringToInt(value);
1928 if (ConfigWhiteListOnly != 1)
1929 {
1930 ConfigWhiteListOnly = 0;
1931 }
1932 }
1933 }
1934 case ConfigStateReasons:
1935 {
1936 Format(g_sReasonKey[iNumReasons], REASON_SIZE, "%s", key);
1937 Format(g_sReasonDisplays[iNumReasons], DISPLAY_SIZE, "%s", value);
1938 #if defined DEBUG
1939 PrintToServer("Loaded reason. index %d, key \"%s\", display_text \"%s\"", iNumReasons, g_sReasonKey[iNumReasons], g_sReasonDisplays[iNumReasons]);
1940 #endif
1941 iNumReasons++;
1942 }
1943 case ConfigStateTimes:
1944 {
1945 Format(g_sTimeDisplays[iNumTimes], DISPLAY_SIZE, "%s", value);
1946 g_iTimeMinutes[iNumTimes] = StringToInt(key);
1947 #if defined DEBUG
1948 PrintToServer("Loaded time. index %d, time %d minutes, display_text \"%s\"", iNumTimes, g_iTimeMinutes[iNumTimes], g_sTimeDisplays[iNumTimes]);
1949 #endif
1950 iNumTimes++;
1951 }
1952 case ConfigStateServers:
1953 {
1954 if (strcmp("id", key, false) == 0)
1955 {
1956 new srvID = StringToInt(value);
1957 if (srvID >= 0)
1958 {
1959 PushArrayCell(g_hServersWhiteList, srvID);
1960 #if defined DEBUG
1961 PrintToServer("Loaded white list server id %d", srvID);
1962 #endif
1963 }
1964 }
1965 }
1966 }
1967 return SMCParse_Continue;
1968}
1969
1970public SMCResult:ReadConfig_EndSection(Handle:smc)
1971{
1972 return SMCParse_Continue;
1973}
1974
1975// STOCK FUNCTIONS //
1976stock setGag(client, length, const String:clientAuth[])
1977{
1978 if (g_GagType[client] == bNot)
1979 {
1980 PerformGag(client, _, length / 60, _, _, _, _);
1981 PrintToChat(client, "%s%t", PREFIX, "Gagged on connect");
1982 LogMessage("%s is gagged from web", clientAuth);
1983 }
1984}
1985
1986stock setMute(client, length, const String:clientAuth[])
1987{
1988 if (g_MuteType[client] == bNot)
1989 {
1990 PerformMute(client, _, length / 60, _, _, _, _);
1991 PrintToChat(client, "%s%t", PREFIX, "Muted on connect");
1992 LogMessage("%s is muted from web", clientAuth);
1993 }
1994}
1995
1996stock bool:DB_Connect()
1997{
1998 #if defined DEBUG
1999 PrintToServer("DB_Connect(handle %d, state %d, lock %d)", g_hDatabase, g_DatabaseState, g_iConnectLock);
2000 #endif
2001
2002 if (g_hDatabase)
2003 {
2004 return true;
2005 }
2006
2007 if (g_DatabaseState == DatabaseState_Wait) // 100500 connections in a minute is bad idea..
2008 {
2009 return false;
2010 }
2011
2012 if (g_DatabaseState != DatabaseState_Connecting)
2013 {
2014 g_DatabaseState = DatabaseState_Connecting;
2015 g_iConnectLock = ++g_iSequence;
2016 // Connect using the "sourcebans" section, or the "default" section if "sourcebans" does not exist
2017 SQL_TConnect(GotDatabase, DATABASE, g_iConnectLock);
2018 }
2019
2020 return false;
2021}
2022
2023stock bool:DB_Conn_Lost(Handle:hndl)
2024{
2025 if (hndl == INVALID_HANDLE)
2026 {
2027 if (g_hDatabase != INVALID_HANDLE)
2028 {
2029 LogError("Lost connection to DB. Reconnect after delay.");
2030 CloseHandle(g_hDatabase);
2031 g_hDatabase = INVALID_HANDLE;
2032 }
2033 if (g_DatabaseState != DatabaseState_Wait)
2034 {
2035 g_DatabaseState = DatabaseState_Wait;
2036 CreateTimer(RetryTime, Timer_StopWait, _, TIMER_FLAG_NO_MAPCHANGE);
2037 }
2038 return true;
2039 }
2040
2041 return false;
2042}
2043
2044stock InitializeBackupDB()
2045{
2046 decl String:error[255];
2047 SQLiteDB = SQLite_UseDatabase("sourcecomms-queue", error, sizeof(error));
2048 if (SQLiteDB == INVALID_HANDLE)
2049 {
2050 SetFailState(error);
2051 }
2052
2053 SQL_TQuery(SQLiteDB, Query_ErrorCheck,
2054 "CREATE TABLE IF NOT EXISTS queue2 ( \
2055 id INTEGER PRIMARY KEY, \
2056 steam_id TEXT, \
2057 time INTEGER, \
2058 start_time INTEGER, \
2059 reason TEXT, \
2060 name TEXT, \
2061 admin_id TEXT, \
2062 admin_ip TEXT, \
2063 type INTEGER)");
2064}
2065
2066stock CreateBlock(client, targetId = 0, length = -1, type, const String:sReason[] = "", const String:sArgs[] = "")
2067{
2068 #if defined DEBUG
2069 PrintToServer("CreateBlock(admin: %d, target: %d, length: %d, type: %d, reason: %s, args: %s)", client, targetId, length, type, sReason, sArgs);
2070 #endif
2071
2072 decl target_list[MAXPLAYERS], target_count, bool:tn_is_ml, String:target_name[MAX_NAME_LENGTH];
2073 new String:reason[256];
2074 new bool:skipped = false;
2075
2076 // checking args
2077 if (targetId)
2078 {
2079 target_list[0] = targetId;
2080 target_count = 1;
2081 tn_is_ml = false;
2082 strcopy(target_name, sizeof(target_name), g_sName[targetId]);
2083 strcopy(reason, sizeof(reason), sReason);
2084 }
2085 else if (strlen(sArgs))
2086 {
2087 new String:sArg[3][192];
2088
2089 if (ExplodeString(sArgs, "\"", sArg, 3, 192, true) == 3 && strlen(sArg[0]) == 0) // exploding by quotes
2090 {
2091 decl String:sTempArg[2][192];
2092 TrimString(sArg[2]);
2093 sArg[0] = sArg[1]; // target name
2094 ExplodeString(sArg[2], " ", sTempArg, 2, 192, true); // get length and reason
2095 sArg[1] = sTempArg[0]; // lenght
2096 sArg[2] = sTempArg[1]; // reason
2097 }
2098 else
2099 {
2100 ExplodeString(sArgs, " ", sArg, 3, 192, true); // exploding by spaces
2101 }
2102
2103 // Get the target, find target returns a message on failure so we do not
2104 if ((target_count = ProcessTargetString(
2105 sArg[0],
2106 client,
2107 target_list,
2108 MAXPLAYERS,
2109 COMMAND_FILTER_NO_BOTS,
2110 target_name,
2111 sizeof(target_name),
2112 tn_is_ml)) <= 0)
2113 {
2114 ReplyToTargetError(client, target_count);
2115 return;
2116 }
2117
2118 // Get the block length
2119 if (!StringToIntEx(sArg[1], length)) // not valid number in second argument
2120 {
2121 length = DefaultTime;
2122 Format(reason, sizeof(reason), "%s %s", sArg[1], sArg[2]);
2123 }
2124 else
2125 {
2126 strcopy(reason, sizeof(reason), sArg[2]);
2127 }
2128
2129 // Strip spaces and quotes from reason
2130 TrimString(reason);
2131 StripQuotes(reason);
2132
2133 if (!IsAllowedBlockLength(client, length, target_count))
2134 {
2135 ReplyToCommand(client, "%s%t", PREFIX, "no access");
2136 return;
2137 }
2138 }
2139 else
2140 {
2141 return;
2142 }
2143
2144 new admImmunity = GetAdmImmunity(client);
2145 decl String:adminAuth[64];
2146
2147 if (client && IsClientInGame(client))
2148 {
2149 GetClientAuthId(client, AuthId_Steam2, adminAuth, sizeof(adminAuth));
2150 }
2151 else
2152 {
2153 // setup dummy adminAuth and adminIp for server
2154 strcopy(adminAuth, sizeof(adminAuth), "STEAM_ID_SERVER");
2155 }
2156
2157 for (new i = 0; i < target_count; i++)
2158 {
2159 new target = target_list[i];
2160
2161 #if defined DEBUG
2162 decl String:auth[64];
2163 GetClientAuthId(target, AuthId_Steam2, auth, sizeof(auth));
2164 PrintToServer("Processing block for %s", auth);
2165 #endif
2166
2167 if (!g_bPlayerStatus[target])
2168 {
2169 // The target has not been blocks verify. It must be completed before you can block anyone.
2170 ReplyToCommand(client, "%s%t", PREFIX, "Player Comms Not Verified");
2171 skipped = true;
2172 continue; // skip
2173 }
2174
2175 switch (type)
2176 {
2177 case TYPE_MUTE:
2178 {
2179 if (!BaseComm_IsClientMuted(target))
2180 {
2181 #if defined DEBUG
2182 PrintToServer("%s not muted. Mute him, creating unmute timer and add record to DB", auth);
2183 #endif
2184
2185 PerformMute(target, _, length, g_sName[client], adminAuth, admImmunity, reason);
2186
2187 LogAction(client, target, "\"%L\" muted \"%L\" (minutes \"%d\") (reason \"%s\")", client, target, length, reason);
2188 }
2189 else
2190 {
2191 #if defined DEBUG
2192 PrintToServer("%s already muted", auth);
2193 #endif
2194
2195 ReplyToCommand(client, "%s%t", PREFIX, "Player already muted", g_sName[target]);
2196
2197 skipped = true;
2198 continue;
2199 }
2200 }
2201 //-------------------------------------------------------------------------------------------------
2202 case TYPE_GAG:
2203 {
2204 if (!BaseComm_IsClientGagged(target))
2205 {
2206 #if defined DEBUG
2207 PrintToServer("%s not gagged. Gag him, creating ungag timer and add record to DB", auth);
2208 #endif
2209
2210 PerformGag(target, _, length, g_sName[client], adminAuth, admImmunity, reason);
2211
2212 LogAction(client, target, "\"%L\" gagged \"%L\" (minutes \"%d\") (reason \"%s\")", client, target, length, reason);
2213 }
2214 else
2215 {
2216 #if defined DEBUG
2217 PrintToServer("%s already gagged", auth);
2218 #endif
2219
2220 ReplyToCommand(client, "%s%t", PREFIX, "Player already gagged", g_sName[target]);
2221
2222 skipped = true;
2223 continue;
2224 }
2225 }
2226 //-------------------------------------------------------------------------------------------------
2227 case TYPE_SILENCE:
2228 {
2229 if (!BaseComm_IsClientGagged(target) && !BaseComm_IsClientMuted(target))
2230 {
2231 #if defined DEBUG
2232 PrintToServer("%s not silenced. Silence him, creating ungag & unmute timers and add records to DB", auth);
2233 #endif
2234
2235 PerformMute(target, _, length, g_sName[client], adminAuth, admImmunity, reason);
2236 PerformGag(target, _, length, g_sName[client], adminAuth, admImmunity, reason);
2237
2238 LogAction(client, target, "\"%L\" silenced \"%L\" (minutes \"%d\") (reason \"%s\")", client, target, length, reason);
2239 }
2240 else
2241 {
2242 #if defined DEBUG
2243 PrintToServer("%s already gagged or/and muted", auth);
2244 #endif
2245
2246 ReplyToCommand(client, "%s%t", PREFIX, "Player already silenced", g_sName[target]);
2247
2248 skipped = true;
2249 continue;
2250 }
2251 }
2252 }
2253 }
2254 if (target_count == 1 && !skipped)
2255 SavePunishment(client, target_list[0], type, length, reason);
2256 if (target_count > 1 || !skipped)
2257 ShowActivityToServer(client, type, length, reason, target_name, tn_is_ml);
2258
2259 return;
2260}
2261
2262stock ProcessUnBlock(client, targetId = 0, type, String:sReason[] = "", const String:sArgs[] = "")
2263{
2264 #if defined DEBUG
2265 PrintToServer("ProcessUnBlock(admin: %d, target: %d, type: %d, reason: %s, args: %s)", client, targetId, type, sReason, sArgs);
2266 #endif
2267
2268 decl target_list[MAXPLAYERS], target_count, bool:tn_is_ml, String:target_name[MAX_NAME_LENGTH];
2269 new String:reason[256];
2270
2271 if (targetId)
2272 {
2273 target_list[0] = targetId;
2274 target_count = 1;
2275 tn_is_ml = false;
2276 strcopy(target_name, sizeof(target_name), g_sName[targetId]);
2277 strcopy(reason, sizeof(reason), sReason);
2278 }
2279 else
2280 {
2281 decl String:sBuffer[256];
2282 new String:sArg[3][192];
2283 GetCmdArgString(sBuffer, sizeof(sBuffer));
2284
2285 if (ExplodeString(sBuffer, "\"", sArg, 3, 192, true) == 3 && strlen(sArg[0]) == 0)
2286 {
2287 TrimString(sArg[2]);
2288 sArg[0] = sArg[1]; // target name
2289 sArg[1] = sArg[2]; // reason; sArg[2] - not in use
2290 }
2291 else
2292 {
2293 ExplodeString(sBuffer, " ", sArg, 2, 192, true);
2294 }
2295 strcopy(reason, sizeof(reason), sArg[1]);
2296 // Strip spaces and quotes from reason
2297 TrimString(reason);
2298 StripQuotes(reason);
2299
2300 // Get the target, find target returns a message on failure so we do not
2301 if ((target_count = ProcessTargetString(
2302 sArg[0],
2303 client,
2304 target_list,
2305 MAXPLAYERS,
2306 COMMAND_FILTER_NO_BOTS,
2307 target_name,
2308 sizeof(target_name),
2309 tn_is_ml)) <= 0)
2310 {
2311 ReplyToTargetError(client, target_count);
2312 return;
2313 }
2314 }
2315
2316 decl String:adminAuth[64];
2317 decl String:targetAuth[64];
2318
2319 if (client && IsClientInGame(client))
2320 {
2321 GetClientAuthId(client, AuthId_Steam2, adminAuth, sizeof(adminAuth));
2322 }
2323 else
2324 {
2325 // setup dummy adminAuth and adminIp for server
2326 strcopy(adminAuth, sizeof(adminAuth), "STEAM_ID_SERVER");
2327 }
2328
2329 if (target_count > 1)
2330 {
2331 #if defined DEBUG
2332 PrintToServer("ProcessUnBlock - targets_count > 1");
2333 #endif
2334
2335 for (new i = 0; i < target_count; i++)
2336 {
2337 new target = target_list[i];
2338
2339 if (IsClientInGame(target))
2340 GetClientAuthId(target, AuthId_Steam2, targetAuth, sizeof(targetAuth));
2341 else
2342 continue;
2343
2344 switch (type)
2345 {
2346 case TYPE_UNMUTE:
2347 {
2348 if (g_MuteType[target] == bTime || g_MuteType[target] == bPerm)
2349 continue;
2350 }
2351 case TYPE_UNGAG:
2352 {
2353 if (g_GagType[target] == bTime || g_GagType[target] == bPerm)
2354 continue;
2355 }
2356 case TYPE_UNSILENCE:
2357 {
2358 if ((g_MuteType[target] == bTime || g_MuteType[target] == bPerm) &&
2359 (g_GagType[target] == bTime || g_GagType[target] == bPerm))
2360 continue;
2361 }
2362 }
2363
2364 new Handle:dataPack = CreateDataPack();
2365 WritePackCell(dataPack, GetClientUserId2(client));
2366 WritePackCell(dataPack, GetClientUserId(target));
2367 WritePackCell(dataPack, type);
2368 WritePackString(dataPack, adminAuth);
2369 WritePackString(dataPack, targetAuth); // not in use in this case
2370 WritePackString(dataPack, reason);
2371
2372 TempUnBlock(dataPack);
2373 }
2374
2375 #if defined DEBUG
2376 PrintToServer("Showing activity to server in ProcessUnBlock for targets_count > 1");
2377 #endif
2378 ShowActivityToServer(client, type + TYPE_TEMP_SHIFT, _, _, target_name, tn_is_ml);
2379 }
2380 else
2381 {
2382 decl String:typeWHERE[100];
2383 new target = target_list[0];
2384
2385 if (IsClientInGame(target))
2386 {
2387 GetClientAuthId(target, AuthId_Steam2, targetAuth, sizeof(targetAuth));
2388 }
2389 else
2390 {
2391 return;
2392 }
2393
2394 switch (type)
2395 {
2396 case TYPE_UNMUTE:
2397 {
2398 if (!BaseComm_IsClientMuted(target))
2399 {
2400 ReplyToCommand(client, "%s%t", PREFIX, "Player not muted");
2401 return;
2402 }
2403 else
2404 FormatEx(typeWHERE, sizeof(typeWHERE), "c.type = '%d'", TYPE_MUTE);
2405 }
2406 //-------------------------------------------------------------------------------------------------
2407 case TYPE_UNGAG:
2408 {
2409 if (!BaseComm_IsClientGagged(target))
2410 {
2411 ReplyToCommand(client, "%s%t", PREFIX, "Player not gagged");
2412 return;
2413 }
2414 else
2415 FormatEx(typeWHERE, sizeof(typeWHERE), "c.type = '%d'", TYPE_GAG);
2416 }
2417 //-------------------------------------------------------------------------------------------------
2418 case TYPE_UNSILENCE:
2419 {
2420 if (!BaseComm_IsClientMuted(target) || !BaseComm_IsClientGagged(target))
2421 {
2422 ReplyToCommand(client, "%s%t", PREFIX, "Player not silenced");
2423 return;
2424 }
2425 else
2426 FormatEx(typeWHERE, sizeof(typeWHERE), "(c.type = '%d' OR c.type = '%d')", TYPE_MUTE, TYPE_GAG);
2427 }
2428 }
2429
2430 // Pack everything into a data pack so we can retain it
2431 new Handle:dataPack = CreateDataPack();
2432 WritePackCell(dataPack, GetClientUserId2(client));
2433 WritePackCell(dataPack, GetClientUserId(target));
2434 WritePackCell(dataPack, type);
2435 WritePackString(dataPack, adminAuth);
2436 WritePackString(dataPack, targetAuth);
2437 WritePackString(dataPack, reason);
2438
2439 // Check current player status. If player has temporary punishment - don't get info from DB
2440 if (DB_Connect())
2441 {
2442 decl String:sAdminAuthEscaped[sizeof(adminAuth) * 2 + 1];
2443 decl String:sAdminAuthYZEscaped[sizeof(adminAuth) * 2 + 1];
2444 decl String:sTargetAuthEscaped[sizeof(targetAuth) * 2 + 1];
2445 decl String:sTargetAuthYZEscaped[sizeof(targetAuth) * 2 + 1];
2446
2447 SQL_EscapeString(g_hDatabase, adminAuth, sAdminAuthEscaped, sizeof(sAdminAuthEscaped));
2448 SQL_EscapeString(g_hDatabase, adminAuth[8], sAdminAuthYZEscaped, sizeof(sAdminAuthYZEscaped));
2449 SQL_EscapeString(g_hDatabase, targetAuth, sTargetAuthEscaped, sizeof(sTargetAuthEscaped));
2450 SQL_EscapeString(g_hDatabase, targetAuth[8], sTargetAuthYZEscaped, sizeof(sTargetAuthYZEscaped));
2451
2452 decl String:query[4096];
2453 Format(query, sizeof(query),
2454 "SELECT c.bid, \
2455 IFNULL((SELECT aid FROM %s_admins WHERE authid = '%s' OR authid REGEXP '^STEAM_[0-9]:%s$'), '0') as iaid, \
2456 c.aid, \
2457 IF (a.immunity>=g.immunity, a.immunity, IFNULL(g.immunity,0)) as immunity, \
2458 c.type \
2459 FROM %s_comms AS c \
2460 LEFT JOIN %s_admins AS a ON a.aid = c.aid \
2461 LEFT JOIN %s_srvgroups AS g ON g.name = a.srv_group \
2462 WHERE RemoveType IS NULL \
2463 AND (c.authid = '%s' OR c.authid REGEXP '^STEAM_[0-9]:%s$') \
2464 AND (length = '0' OR ends > UNIX_TIMESTAMP()) \
2465 AND %s",
2466 DatabasePrefix, sAdminAuthEscaped, sAdminAuthYZEscaped, DatabasePrefix, DatabasePrefix, DatabasePrefix, sTargetAuthEscaped, sTargetAuthYZEscaped, typeWHERE);
2467
2468 #if defined LOG_QUERIES
2469 LogToFile(logQuery, "ProcessUnBlock. QUERY: %s", query);
2470 #endif
2471
2472 SQL_TQuery(g_hDatabase, Query_UnBlockSelect, query, dataPack);
2473 }
2474 else
2475 {
2476 #if defined DEBUG
2477 PrintToServer("Calling TempUnBlock from ProcessUnBlock");
2478 #endif
2479
2480 if (TempUnBlock(dataPack))
2481 ShowActivityToServer(client, type + TYPE_TEMP_SHIFT, _, _, g_sName[target], _);
2482 }
2483 }
2484}
2485
2486stock bool:TempUnBlock(Handle:data)
2487{
2488 decl String:adminAuth[30], String:targetAuth[30];
2489 new String:reason[256];
2490 ResetPack(data);
2491 new adminUserID = ReadPackCell(data);
2492 new targetUserID = ReadPackCell(data);
2493 new type = ReadPackCell(data);
2494 ReadPackString(data, adminAuth, sizeof(adminAuth));
2495 ReadPackString(data, targetAuth, sizeof(targetAuth));
2496 ReadPackString(data, reason, sizeof(reason));
2497 CloseHandle(data); // Need to close datapack
2498
2499 #if defined DEBUG
2500 PrintToServer("TempUnBlock(adminUID: %d, targetUID: %d, type: %d, adminAuth: %s, targetAuth: %s, reason: %s)", adminUserID, targetUserID, type, adminAuth, targetAuth, reason);
2501 #endif
2502
2503 new admin = GetClientOfUserId(adminUserID);
2504 new target = GetClientOfUserId(targetUserID);
2505 if (!target)
2506 return false; // target has gone away
2507
2508 new AdmImmunity = GetAdmImmunity(admin);
2509 new bool:AdmImCheck = (DisUBImCheck == 0
2510 && ((type == TYPE_UNMUTE && AdmImmunity >= g_iMuteLevel[target])
2511 || (type == TYPE_UNGAG && AdmImmunity >= g_iGagLevel[target])
2512 || (type == TYPE_UNSILENCE && AdmImmunity >= g_iMuteLevel[target]
2513 && AdmImmunity >= g_iGagLevel[target])
2514 )
2515 );
2516
2517 #if defined DEBUG
2518 PrintToServer("WHO WE ARE CHECKING!");
2519 if (!admin)
2520 PrintToServer("we are console (possibly)");
2521 if (AdmHasFlag(admin))
2522 PrintToServer("we have special flag");
2523 #endif
2524
2525 // Check access for unblock without db changes (temporary unblock)
2526 new bool:bHasPermission = (!admin && StrEqual(adminAuth, "STEAM_ID_SERVER")) || AdmHasFlag(admin) || AdmImCheck;
2527 // can, if we are console or have special flag. else - deep checking by issuer authid
2528 if (!bHasPermission) {
2529 switch (type)
2530 {
2531 case TYPE_UNMUTE:
2532 {
2533 bHasPermission = StrEqual(adminAuth, g_sMuteAdminAuth[target]);
2534 }
2535 case TYPE_UNGAG:
2536 {
2537 bHasPermission = StrEqual(adminAuth, g_sGagAdminAuth[target]);
2538 }
2539 case TYPE_UNSILENCE:
2540 {
2541 bHasPermission = StrEqual(adminAuth, g_sMuteAdminAuth[target]) && StrEqual(adminAuth, g_sGagAdminAuth[target]);
2542 }
2543 }
2544 }
2545
2546 if (bHasPermission)
2547 {
2548 switch (type)
2549 {
2550 case TYPE_UNMUTE:
2551 {
2552 PerformUnMute(target);
2553 LogAction(admin, target, "\"%L\" temporary unmuted \"%L\" (reason \"%s\")", admin, target, reason);
2554 }
2555 //-------------------------------------------------------------------------------------------------
2556 case TYPE_UNGAG:
2557 {
2558 PerformUnGag(target);
2559 LogAction(admin, target, "\"%L\" temporary ungagged \"%L\" (reason \"%s\")", admin, target, reason);
2560 }
2561 //-------------------------------------------------------------------------------------------------
2562 case TYPE_UNSILENCE:
2563 {
2564 PerformUnMute(target);
2565 PerformUnGag(target);
2566 LogAction(admin, target, "\"%L\" temporary unsilenced \"%L\" (reason \"%s\")", admin, target, reason);
2567 }
2568 default:
2569 {
2570 return false;
2571 }
2572 }
2573 return true;
2574 }
2575 else
2576 {
2577 if (admin && IsClientInGame(admin))
2578 {
2579 PrintToChat(admin, "%s%t", PREFIX, "No db error unlock perm");
2580 PrintToConsole(admin, "%s%t", PREFIX, "No db error unlock perm");
2581 }
2582 return false;
2583 }
2584}
2585
2586stock InsertTempBlock(length, type, const String:name[], const String:auth[], const String:reason[], const String:adminAuth[], const String:adminIp[])
2587{
2588 LogMessage("Saving punishment for %s into queue", auth);
2589
2590 decl String:banName[MAX_NAME_LENGTH * 2 + 1];
2591 decl String:banReason[256 * 2 + 1];
2592 decl String:sAuthEscaped[64 * 2 + 1];
2593 decl String:sAdminAuthEscaped[64 * 2 + 1];
2594 decl String:sQuery[4096], String:sQueryVal[2048];
2595 new String:sQueryMute[2048], String:sQueryGag[2048];
2596
2597 // escaping everything
2598 SQL_EscapeString(SQLiteDB, name, banName, sizeof(banName));
2599 SQL_EscapeString(SQLiteDB, reason, banReason, sizeof(banReason));
2600 SQL_EscapeString(SQLiteDB, auth, sAuthEscaped, sizeof(sAuthEscaped));
2601 SQL_EscapeString(SQLiteDB, adminAuth, sAdminAuthEscaped, sizeof(sAdminAuthEscaped));
2602
2603 // steam_id time start_time reason name admin_id admin_ip
2604 FormatEx(sQueryVal, sizeof(sQueryVal),
2605 "'%s', %d, %d, '%s', '%s', '%s', '%s'",
2606 sAuthEscaped, length, GetTime(), banReason, banName, sAdminAuthEscaped, adminIp);
2607
2608 switch (type)
2609 {
2610 case TYPE_MUTE:FormatEx(sQueryMute, sizeof(sQueryMute), "(%s, %d)", sQueryVal, type);
2611 case TYPE_GAG:FormatEx(sQueryGag, sizeof(sQueryGag), "(%s, %d)", sQueryVal, type);
2612 case TYPE_SILENCE:
2613 {
2614 FormatEx(sQueryMute, sizeof(sQueryMute), "(%s, %d)", sQueryVal, TYPE_MUTE);
2615 FormatEx(sQueryGag, sizeof(sQueryGag), "(%s, %d)", sQueryVal, TYPE_GAG);
2616 }
2617 }
2618
2619 FormatEx(sQuery, sizeof(sQuery),
2620 "INSERT INTO queue2 (steam_id, time, start_time, reason, name, admin_id, admin_ip, type) VALUES %s%s%s",
2621 sQueryMute, type == TYPE_SILENCE ? ", " : "", sQueryGag);
2622
2623 #if defined LOG_QUERIES
2624 LogToFile(logQuery, "InsertTempBlock. QUERY: %s", sQuery);
2625 #endif
2626
2627 SQL_TQuery(SQLiteDB, Query_ErrorCheck, sQuery);
2628}
2629
2630stock ServerInfo()
2631{
2632 decl pieces[4];
2633 new longip = GetConVarInt(CvarHostIp);
2634 pieces[0] = (longip >> 24) & 0x000000FF;
2635 pieces[1] = (longip >> 16) & 0x000000FF;
2636 pieces[2] = (longip >> 8) & 0x000000FF;
2637 pieces[3] = longip & 0x000000FF;
2638 FormatEx(ServerIp, sizeof(ServerIp), "%d.%d.%d.%d", pieces[0], pieces[1], pieces[2], pieces[3]);
2639 GetConVarString(CvarPort, ServerPort, sizeof(ServerPort));
2640}
2641
2642stock ReadConfig()
2643{
2644 InitializeConfigParser();
2645
2646 if (ConfigParser == INVALID_HANDLE)
2647 {
2648 return;
2649 }
2650
2651 decl String:ConfigFile1[PLATFORM_MAX_PATH], String:ConfigFile2[PLATFORM_MAX_PATH];
2652 BuildPath(Path_SM, ConfigFile1, sizeof(ConfigFile1), "configs/sourcebans/sourcebans.cfg");
2653 BuildPath(Path_SM, ConfigFile2, sizeof(ConfigFile2), "configs/sourcebans/sourcecomms.cfg");
2654
2655 if (FileExists(ConfigFile1))
2656 {
2657 PrintToServer("%sLoading configs/sourcebans/sourcebans.cfg config file", PREFIX);
2658 InternalReadConfig(ConfigFile1);
2659 }
2660 else
2661 {
2662 SetFailState("FATAL *** ERROR *** can't find %s", ConfigFile1);
2663 }
2664 if (FileExists(ConfigFile2))
2665 {
2666 PrintToServer("%sLoading configs/sourcecomms.cfg config file", PREFIX);
2667 iNumReasons = 0;
2668 iNumTimes = 0;
2669 InternalReadConfig(ConfigFile2);
2670 if (iNumReasons)
2671 iNumReasons--;
2672 if (iNumTimes)
2673 iNumTimes--;
2674 if (serverID == 0)
2675 {
2676 LogError("You must set valid `ServerID` value in sourcebans.cfg!");
2677 if (ConfigWhiteListOnly)
2678 {
2679 LogError("ServersWhiteList feature disabled!");
2680 ConfigWhiteListOnly = 0;
2681 }
2682 }
2683 }
2684 else
2685 {
2686 SetFailState("FATAL *** ERROR *** can't find %s", ConfigFile2);
2687 }
2688 #if defined DEBUG
2689 PrintToServer("Loaded DefaultTime value: %d", DefaultTime);
2690 PrintToServer("Loaded DisableUnblockImmunityCheck value: %d", DisUBImCheck);
2691 #endif
2692}
2693
2694
2695// some more
2696
2697AdminMenu_GetPunishPhrase(client, target, String:name[], length)
2698{
2699 decl String:Buffer[192];
2700 if (g_MuteType[target] > bNot && g_GagType[target] > bNot)
2701 Format(Buffer, sizeof(Buffer), "%T", "AdminMenu_Display_Silenced", client, name);
2702 else if (g_MuteType[target] > bNot)
2703 Format(Buffer, sizeof(Buffer), "%T", "AdminMenu_Display_Muted", client, name);
2704 else if (g_GagType[target] > bNot)
2705 Format(Buffer, sizeof(Buffer), "%T", "AdminMenu_Display_Gagged", client, name);
2706 else
2707 Format(Buffer, sizeof(Buffer), "%T", "AdminMenu_Display_None", client, name);
2708
2709 strcopy(name, length, Buffer);
2710}
2711
2712bool:Bool_ValidMenuTarget(client, target)
2713{
2714 if (target <= 0)
2715 {
2716 if (client)
2717 PrintToChat(client, "%s%t", PREFIX, "AdminMenu_Not_Available");
2718 else
2719 ReplyToCommand(client, "%s%t", PREFIX, "AdminMenu_Not_Available");
2720
2721 return false;
2722 }
2723 else if (!CanUserTarget(client, target))
2724 {
2725 if (client)
2726 PrintToChat(client, "%s%t", PREFIX, "Command_Target_Not_Targetable");
2727 else
2728 ReplyToCommand(client, "%s%t", PREFIX, "Command_Target_Not_Targetable");
2729
2730 return false;
2731 }
2732
2733 return true;
2734}
2735
2736stock bool:IsAllowedBlockLength(admin, length, target_count = 1)
2737{
2738 if (target_count == 1)
2739 {
2740 // Restriction disabled, all allowed for console, all allowed for admins with special flag
2741 if (!ConfigMaxLength || !admin || AdmHasFlag(admin))
2742 return true;
2743
2744 //return false if one of these statements evaluates to true; otherwise, return true
2745 return !(!length || length > ConfigMaxLength);
2746 }
2747 else
2748 {
2749 if (length < 0) //'session punishments allowed for mass-targeting'
2750 return true;
2751
2752 //return false if one of these statements evaluates to true; otherwise, return true
2753 return !(!length || length > MAX_TIME_MULTI || length > DefaultTime);
2754 }
2755}
2756
2757stock bool:AdmHasFlag(admin)
2758{
2759 return admin && CheckCommandAccess(admin, "", UNBLOCK_FLAG, true);
2760}
2761
2762stock _:GetAdmImmunity(admin)
2763{
2764 return admin > 0 && GetUserAdmin(admin) != INVALID_ADMIN_ID ?
2765 GetAdminImmunityLevel(GetUserAdmin(admin)) : 0;
2766}
2767
2768stock _:GetClientUserId2(client)
2769{
2770 return client ? GetClientUserId(client) : 0; // 0 is for CONSOLE
2771}
2772
2773stock ForcePlayersRecheck()
2774{
2775 for (new i = 1; i <= MaxClients; i++)
2776 {
2777 if (IsClientInGame(i) && IsClientAuthorized(i) && !IsFakeClient(i) && g_hPlayerRecheck[i] == INVALID_HANDLE)
2778 {
2779 #if defined DEBUG
2780 {
2781 decl String:clientAuth[64];
2782 GetClientAuthId(i, AuthId_Steam2, clientAuth, sizeof(clientAuth));
2783 PrintToServer("Creating Recheck timer for %s", clientAuth);
2784 }
2785 #endif
2786 g_hPlayerRecheck[i] = CreateTimer(float(i), ClientRecheck, GetClientUserId(i));
2787 }
2788 }
2789}
2790
2791stock bool:NotApplyToThisServer(srvID)
2792{
2793 return ConfigWhiteListOnly && FindValueInArray(g_hServersWhiteList, srvID) == -1;
2794}
2795
2796stock MarkClientAsUnMuted(target)
2797{
2798 g_MuteType[target] = bNot;
2799 g_iMuteTime[target] = 0;
2800 g_iMuteLength[target] = 0;
2801 g_iMuteLevel[target] = -1;
2802 g_sMuteAdminName[target][0] = '\0';
2803 g_sMuteReason[target][0] = '\0';
2804 g_sMuteAdminAuth[target][0] = '\0';
2805}
2806
2807stock MarkClientAsUnGagged(target)
2808{
2809 g_GagType[target] = bNot;
2810 g_iGagTime[target] = 0;
2811 g_iGagLength[target] = 0;
2812 g_iGagLevel[target] = -1;
2813 g_sGagAdminName[target][0] = '\0';
2814 g_sGagReason[target][0] = '\0';
2815 g_sGagAdminAuth[target][0] = '\0';
2816}
2817
2818stock MarkClientAsMuted(target, time = NOW, length = -1, const String:adminName[] = "CONSOLE", const String:adminAuth[] = "STEAM_ID_SERVER", adminImmunity = 0, const String:reason[] = "")
2819{
2820 if (time)
2821 g_iMuteTime[target] = time;
2822 else
2823 g_iMuteTime[target] = GetTime();
2824
2825 g_iMuteLength[target] = length;
2826 g_iMuteLevel[target] = adminImmunity ? adminImmunity : ConsoleImmunity;
2827 strcopy(g_sMuteAdminName[target], sizeof(g_sMuteAdminName[]), adminName);
2828 strcopy(g_sMuteReason[target], sizeof(g_sMuteReason[]), reason);
2829 strcopy(g_sMuteAdminAuth[target], sizeof(g_sMuteAdminAuth[]), adminAuth);
2830
2831 if (length > 0)
2832 g_MuteType[target] = bTime;
2833 else if (length == 0)
2834 g_MuteType[target] = bPerm;
2835 else
2836 g_MuteType[target] = bSess;
2837}
2838
2839stock MarkClientAsGagged(target, time = NOW, length = -1, const String:adminName[] = "CONSOLE", const String:adminAuth[] = "STEAM_ID_SERVER", adminImmunity = 0, const String:reason[] = "")
2840{
2841 if (time)
2842 g_iGagTime[target] = time;
2843 else
2844 g_iGagTime[target] = GetTime();
2845
2846 g_iGagLength[target] = length;
2847 g_iGagLevel[target] = adminImmunity ? adminImmunity : ConsoleImmunity;
2848 strcopy(g_sGagAdminName[target], sizeof(g_sGagAdminName[]), adminName);
2849 strcopy(g_sGagReason[target], sizeof(g_sGagReason[]), reason);
2850 strcopy(g_sGagAdminAuth[target], sizeof(g_sGagAdminAuth[]), adminAuth);
2851
2852 if (length > 0)
2853 g_GagType[target] = bTime;
2854 else if (length == 0)
2855 g_GagType[target] = bPerm;
2856 else
2857 g_GagType[target] = bSess;
2858}
2859
2860stock CloseMuteExpireTimer(target)
2861{
2862 if (g_hMuteExpireTimer[target] != INVALID_HANDLE && CloseHandle(g_hMuteExpireTimer[target]))
2863 g_hMuteExpireTimer[target] = INVALID_HANDLE;
2864}
2865
2866stock CloseGagExpireTimer(target)
2867{
2868 if (g_hGagExpireTimer[target] != INVALID_HANDLE && CloseHandle(g_hGagExpireTimer[target]))
2869 g_hGagExpireTimer[target] = INVALID_HANDLE;
2870}
2871
2872stock CreateMuteExpireTimer(target, remainingTime = 0)
2873{
2874 if (g_iMuteLength[target] > 0)
2875 {
2876 new Handle:hPack;
2877
2878 if (remainingTime)
2879 g_hMuteExpireTimer[target] = CreateDataTimer(float(remainingTime), Timer_MuteExpire, hPack, TIMER_FLAG_NO_MAPCHANGE);
2880 else
2881 g_hMuteExpireTimer[target] = CreateDataTimer(float(g_iMuteLength[target] * 60), Timer_MuteExpire, hPack, TIMER_FLAG_NO_MAPCHANGE);
2882
2883 WritePackCell(hPack, target);
2884 WritePackCell(hPack, GetClientUserId(target));
2885 }
2886}
2887
2888stock CreateGagExpireTimer(target, remainingTime = 0)
2889{
2890 if (g_iGagLength[target] > 0)
2891 {
2892 new Handle:hPack;
2893
2894 if (remainingTime)
2895 g_hGagExpireTimer[target] = CreateDataTimer(float(remainingTime), Timer_GagExpire, hPack, TIMER_FLAG_NO_MAPCHANGE);
2896 else
2897 g_hGagExpireTimer[target] = CreateDataTimer(float(g_iGagLength[target] * 60), Timer_GagExpire, hPack, TIMER_FLAG_NO_MAPCHANGE);
2898
2899 WritePackCell(hPack, target);
2900 WritePackCell(hPack, GetClientUserId(target));
2901 }
2902}
2903
2904stock PerformUnMute(target)
2905{
2906 MarkClientAsUnMuted(target);
2907 BaseComm_SetClientMute(target, false);
2908 CloseMuteExpireTimer(target);
2909}
2910
2911stock PerformUnGag(target)
2912{
2913 MarkClientAsUnGagged(target);
2914 BaseComm_SetClientGag(target, false);
2915 CloseGagExpireTimer(target);
2916}
2917
2918stock PerformMute(target, time = NOW, length = -1, const String:adminName[] = "CONSOLE", const String:adminAuth[] = "STEAM_ID_SERVER", adminImmunity = 0, const String:reason[] = "", remaining_time = 0)
2919{
2920 MarkClientAsMuted(target, time, length, adminName, adminAuth, adminImmunity, reason);
2921 BaseComm_SetClientMute(target, true);
2922 CreateMuteExpireTimer(target, remaining_time);
2923}
2924
2925stock PerformGag(target, time = NOW, length = -1, const String:adminName[] = "CONSOLE", const String:adminAuth[] = "STEAM_ID_SERVER", adminImmunity = 0, const String:reason[] = "", remaining_time = 0)
2926{
2927 MarkClientAsGagged(target, time, length, adminName, adminAuth, adminImmunity, reason);
2928 BaseComm_SetClientGag(target, true);
2929 CreateGagExpireTimer(target, remaining_time);
2930}
2931
2932stock SavePunishment(admin = 0, target, type, length = -1, const String:reason[] = "")
2933{
2934 if (type < TYPE_MUTE || type > TYPE_SILENCE)
2935 return;
2936
2937 // target information
2938 decl String:targetAuth[64];
2939 if (IsClientInGame(target))
2940 {
2941 GetClientAuthId(target, AuthId_Steam2, targetAuth, sizeof(targetAuth));
2942 }
2943 else
2944 {
2945 return;
2946 }
2947
2948 decl String:adminIp[24];
2949 decl String:adminAuth[64];
2950 if (admin && IsClientInGame(admin))
2951 {
2952 GetClientIP(admin, adminIp, sizeof(adminIp));
2953 GetClientAuthId(admin, AuthId_Steam2, adminAuth, sizeof(adminAuth));
2954 }
2955 else
2956 {
2957 // setup dummy adminAuth and adminIp for server
2958 strcopy(adminAuth, sizeof(adminAuth), "STEAM_ID_SERVER");
2959 strcopy(adminIp, sizeof(adminIp), ServerIp);
2960 }
2961
2962 decl String:sName[MAX_NAME_LENGTH];
2963 strcopy(sName, sizeof(sName), g_sName[target]);
2964
2965 if (DB_Connect())
2966 {
2967 // Accepts length in minutes, writes to db in seconds! In all over places in plugin - length is in minutes.
2968 decl String:banName[MAX_NAME_LENGTH * 2 + 1];
2969 decl String:banReason[256 * 2 + 1];
2970 decl String:sAuthidEscaped[64 * 2 + 1];
2971 decl String:sAdminAuthIdEscaped[64 * 2 + 1];
2972 decl String:sAdminAuthIdYZEscaped[64 * 2 + 1];
2973 decl String:sQuery[4096], String:sQueryAdm[512], String:sQueryVal[1024];
2974 decl String:sQueryMute[1024], String:sQueryGag[1024];
2975 sQueryMute[0] = 0;
2976 sQueryGag[0] = 0;
2977
2978 // escaping everything
2979 SQL_EscapeString(g_hDatabase, sName, banName, sizeof(banName));
2980 SQL_EscapeString(g_hDatabase, reason, banReason, sizeof(banReason));
2981 SQL_EscapeString(g_hDatabase, targetAuth, sAuthidEscaped, sizeof(sAuthidEscaped));
2982 SQL_EscapeString(g_hDatabase, adminAuth, sAdminAuthIdEscaped, sizeof(sAdminAuthIdEscaped));
2983 SQL_EscapeString(g_hDatabase, adminAuth[8], sAdminAuthIdYZEscaped, sizeof(sAdminAuthIdYZEscaped));
2984
2985 // bid authid name created ends lenght reason aid adminip sid removedBy removedType removedon type ureason
2986 FormatEx(sQueryAdm, sizeof(sQueryAdm),
2987 "IFNULL((SELECT aid FROM %s_admins WHERE authid = '%s' OR authid REGEXP '^STEAM_[0-9]:%s$'), 0)",
2988 DatabasePrefix, sAdminAuthIdEscaped, sAdminAuthIdYZEscaped);
2989
2990 if (length >= 0)
2991 {
2992 // authid name, created, ends, length, reason, aid, adminIp, sid
2993 FormatEx(sQueryVal, sizeof(sQueryVal),
2994 "'%s', '%s', UNIX_TIMESTAMP(), UNIX_TIMESTAMP() + %d, %d, '%s', %s, '%s', %d",
2995 sAuthidEscaped, banName, length * 60, length * 60, banReason, sQueryAdm, adminIp, serverID);
2996 }
2997 else // Session mutes
2998 {
2999 // authid name, created, ends, length, reason, aid, adminIp, sid
3000 FormatEx(sQueryVal, sizeof(sQueryVal),
3001 "'%s', '%s', UNIX_TIMESTAMP(), UNIX_TIMESTAMP() + %d, %d, '%s', %s, '%s', %d",
3002 sAuthidEscaped, banName, SESSION_MUTE_FALLBACK, -1, banReason, sQueryAdm, adminIp, serverID);
3003 }
3004
3005 switch (type)
3006 {
3007 case TYPE_GAG:FormatEx(sQueryGag, sizeof(sQueryGag), "(%s, %d)", sQueryVal, type);
3008 case TYPE_MUTE:FormatEx(sQueryMute, sizeof(sQueryMute), "(%s, %d)", sQueryVal, type);
3009 case TYPE_SILENCE:
3010 {
3011 FormatEx(sQueryMute, sizeof(sQueryMute), "(%s, %d)", sQueryVal, TYPE_MUTE);
3012 FormatEx(sQueryGag, sizeof(sQueryGag), "(%s, %d)", sQueryVal, TYPE_GAG);
3013 }
3014 }
3015
3016 // litle magic - one query for all actions (mute, gag or silence)
3017 FormatEx(sQuery, sizeof(sQuery),
3018 "INSERT INTO %s_comms (authid, name, created, ends, length, reason, aid, adminIp, sid, type) VALUES %s%s%s",
3019 DatabasePrefix, sQueryMute, type == TYPE_SILENCE ? ", " : "", sQueryGag);
3020
3021 #if defined LOG_QUERIES
3022 LogToFile(logQuery, "SavePunishment. QUERY: %s", sQuery);
3023 #endif
3024
3025 // all data cached before calling asynchronous functions
3026 new Handle:dataPack = CreateDataPack();
3027 WritePackCell(dataPack, admin > 0 ? GetClientUserId(admin) : 0);
3028 WritePackCell(dataPack, GetClientUserId(target));
3029 WritePackCell(dataPack, length);
3030 WritePackCell(dataPack, type);
3031 WritePackString(dataPack, reason);
3032 WritePackString(dataPack, sName);
3033 WritePackString(dataPack, targetAuth);
3034 WritePackString(dataPack, adminAuth);
3035 WritePackString(dataPack, adminIp);
3036
3037 SQL_TQuery(g_hDatabase, Query_AddBlockInsert, sQuery, dataPack, DBPrio_High);
3038 }
3039 else
3040 InsertTempBlock(length, type, sName, targetAuth, reason, adminAuth, adminIp);
3041}
3042
3043stock ShowActivityToServer(admin, type, length = 0, String:reason[] = "", String:targetName[], bool:ml = false)
3044{
3045 #if defined DEBUG
3046 PrintToServer("ShowActivityToServer(admin: %d, type: %d, length: %d, reason: %s, name: %s, ml: %b",
3047 admin, type, length, reason, targetName, ml);
3048 #endif
3049
3050 decl String:actionName[32], String:translationName[64];
3051 switch (type)
3052 {
3053 case TYPE_MUTE:
3054 {
3055 if (length > 0)
3056 strcopy(actionName, sizeof(actionName), "Muted");
3057 else if (length == 0)
3058 strcopy(actionName, sizeof(actionName), "Permamuted");
3059 else // temp block
3060 strcopy(actionName, sizeof(actionName), "Temp muted");
3061 }
3062 //-------------------------------------------------------------------------------------------------
3063 case TYPE_GAG:
3064 {
3065 if (length > 0)
3066 strcopy(actionName, sizeof(actionName), "Gagged");
3067 else if (length == 0)
3068 strcopy(actionName, sizeof(actionName), "Permagagged");
3069 else //temp block
3070 strcopy(actionName, sizeof(actionName), "Temp gagged");
3071 }
3072 //-------------------------------------------------------------------------------------------------
3073 case TYPE_SILENCE:
3074 {
3075 if (length > 0)
3076 strcopy(actionName, sizeof(actionName), "Silenced");
3077 else if (length == 0)
3078 strcopy(actionName, sizeof(actionName), "Permasilenced");
3079 else //temp block
3080 strcopy(actionName, sizeof(actionName), "Temp silenced");
3081 }
3082 //-------------------------------------------------------------------------------------------------
3083 case TYPE_UNMUTE:
3084 {
3085 strcopy(actionName, sizeof(actionName), "Unmuted");
3086 }
3087 //-------------------------------------------------------------------------------------------------
3088 case TYPE_UNGAG:
3089 {
3090 strcopy(actionName, sizeof(actionName), "Ungagged");
3091 }
3092 //-------------------------------------------------------------------------------------------------
3093 case TYPE_TEMP_UNMUTE:
3094 {
3095 strcopy(actionName, sizeof(actionName), "Temp unmuted");
3096 }
3097 //-------------------------------------------------------------------------------------------------
3098 case TYPE_TEMP_UNGAG:
3099 {
3100 strcopy(actionName, sizeof(actionName), "Temp ungagged");
3101 }
3102 //-------------------------------------------------------------------------------------------------
3103 case TYPE_TEMP_UNSILENCE:
3104 {
3105 strcopy(actionName, sizeof(actionName), "Temp unsilenced");
3106 }
3107 //-------------------------------------------------------------------------------------------------
3108 default:
3109 {
3110 return;
3111 }
3112 }
3113
3114 Format(translationName, sizeof(translationName), "%s %s", actionName, reason[0] == '\0' ? "player" : "player reason");
3115 #if defined DEBUG
3116 PrintToServer("translation name: %s", translationName);
3117 #endif
3118
3119 if (length > 0)
3120 {
3121 if (ml)
3122 ShowActivity2(admin, PREFIX, "%t", translationName, targetName, length, reason);
3123 else
3124 ShowActivity2(admin, PREFIX, "%t", translationName, "_s", targetName, length, reason);
3125 }
3126 else
3127 {
3128 if (ml)
3129 ShowActivity2(admin, PREFIX, "%t", translationName, targetName, reason);
3130 else
3131 ShowActivity2(admin, PREFIX, "%t", translationName, "_s", targetName, reason);
3132 }
3133}
3134
3135// Natives //
3136public Native_SetClientMute(Handle hPlugin, int numParams)
3137{
3138 int target = GetNativeCell(1);
3139 if (target < 1 || target > MaxClients)
3140 {
3141 ThrowNativeError(SP_ERROR_NATIVE, "Invalid client index %d", target);
3142 return false;
3143 }
3144
3145 if (!IsClientInGame(target))
3146 {
3147 ThrowNativeError(SP_ERROR_NATIVE, "Client %d is not in game", target);
3148 return false;
3149 }
3150
3151 bool muteState = bool:GetNativeCell(2);
3152 int muteLength = GetNativeCell(3);
3153
3154 if (muteState && muteLength == 0)
3155 {
3156 ThrowNativeError(SP_ERROR_NATIVE, "Permanent mute is not allowed!");
3157 return false;
3158 }
3159
3160 bool bSaveToDB = bool:GetNativeCell(4);
3161 if (!muteState && bSaveToDB)
3162 {
3163 ThrowNativeError(SP_ERROR_NATIVE, "Removing punishments from DB is not allowed!");
3164 return false;
3165 }
3166
3167 char sReason[256];
3168 GetNativeString(5, sReason, sizeof(sReason));
3169
3170 if (muteState)
3171 {
3172 if (g_MuteType[target] > bNot)
3173 {
3174 return false;
3175 }
3176
3177 PerformMute(target, _, muteLength, _, _, _, sReason);
3178 if (bSaveToDB)
3179 SavePunishment(_, target, TYPE_MUTE, muteLength, sReason);
3180 }
3181 else
3182 {
3183 if (g_MuteType[target] == bNot)
3184 {
3185 return false;
3186 }
3187
3188 PerformUnMute(target);
3189 }
3190
3191 return true;
3192}
3193
3194public Native_SetClientGag(Handle:hPlugin, numParams)
3195{
3196 new target = GetNativeCell(1);
3197 if (target < 1 || target > MaxClients)
3198 {
3199 return ThrowNativeError(SP_ERROR_NATIVE, "Invalid client index %d", target);
3200 }
3201
3202 if (!IsClientInGame(target))
3203 {
3204 return ThrowNativeError(SP_ERROR_NATIVE, "Client %d is not in game", target);
3205 }
3206
3207 new bool:gagState = GetNativeCell(2);
3208 new gagLength = GetNativeCell(3);
3209 if (gagState && gagLength == 0)
3210 {
3211 return ThrowNativeError(SP_ERROR_NATIVE, "Permanent gag is not allowed!");
3212 }
3213
3214 new bool:bSaveToDB = GetNativeCell(4);
3215 if (!gagState && bSaveToDB)
3216 {
3217 return ThrowNativeError(SP_ERROR_NATIVE, "Removing punishments from DB is not allowed!");
3218 }
3219
3220 new String:sReason[256];
3221 GetNativeString(5, sReason, sizeof(sReason));
3222
3223 if (gagState)
3224 {
3225 if (g_GagType[target] > bNot)
3226 {
3227 return false;
3228 }
3229
3230 PerformGag(target, _, gagLength, _, _, _, sReason);
3231
3232 if (bSaveToDB)
3233 SavePunishment(_, target, TYPE_GAG, gagLength, sReason);
3234 }
3235 else
3236 {
3237 if (g_GagType[target] == bNot)
3238 {
3239 return false;
3240 }
3241
3242 PerformUnGag(target);
3243 }
3244
3245 return true;
3246}
3247
3248public Native_GetClientMuteType(Handle:hPlugin, numParams)
3249{
3250 new target = GetNativeCell(1);
3251 if (target < 1 || target > MaxClients)
3252 {
3253 return ThrowNativeError(SP_ERROR_NATIVE, "Invalid client index %d", target);
3254 }
3255
3256 if (!IsClientInGame(target))
3257 {
3258 return ThrowNativeError(SP_ERROR_NATIVE, "Client %d is not in game", target);
3259 }
3260
3261 return bType:g_MuteType[target];
3262}
3263
3264public Native_GetClientGagType(Handle:hPlugin, numParams)
3265{
3266 new target = GetNativeCell(1);
3267 if (target < 1 || target > MaxClients)
3268 {
3269 return ThrowNativeError(SP_ERROR_NATIVE, "Invalid client index %d", target);
3270 }
3271
3272 if (!IsClientInGame(target))
3273 {
3274 return ThrowNativeError(SP_ERROR_NATIVE, "Client %d is not in game", target);
3275 }
3276
3277 return bType:g_GagType[target];
3278}
3279//Yarr!