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