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