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