/** * ----------------------------------------------------- * File calladmin.sp * Authors Impact, dordnung * License GPLv3 * Web http://gugyclan.eu, https://dordnung.de * ----------------------------------------------------- * * CallAdmin * Copyright (C) 2013-2018 Impact, dordnung * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ #include #include "include/autoexecconfig" #include "include/calladmin" #include "include/calladmin_stocks" #undef REQUIRE_PLUGIN #include #pragma semicolon 1 #pragma newdecls required // Banreasons ArrayList g_hReasonAdt; char g_sReasonConfigFile[PLATFORM_MAX_PATH]; // Global Stuff ConVar g_hServerName; char g_sServerName[64]; ConVar g_hVersion; ConVar g_hHostPort; int g_iHostPort; ConVar g_hHostIP; char g_sHostIP[16]; Handle g_hAdvertTimer; ConVar g_hAdvertInterval; float g_fAdvertInterval; ConVar g_hPublicMessage; bool g_bPublicMessage; ConVar g_hOwnReason; bool g_bOwnReason; ConVar g_hConfirmCall; bool g_bConfirmCall; ConVar g_hSpamTime; int g_iSpamTime; ConVar g_hReportTime; int g_iReportTime; ConVar g_hAdminAction; int g_iAdminAction; // Report id used for handling int g_iCurrentReportID; // List of not handled IDs ArrayList g_hActiveReports; // Log file char g_sLogFile[PLATFORM_MAX_PATH]; #define ADMIN_ACTION_PASS 0 #define ADMIN_ACTION_BLOCK_MESSAGE 1 int g_iCurrentTrackers; // Current target info g_iTarget[MAXPLAYERS + 1]; char g_sTargetReason[MAXPLAYERS + 1][REASON_MAX_LENGTH]; // Is this player writing his own reason? bool g_bAwaitingReason[MAXPLAYERS +1]; // When has this user reported the last time g_iLastReport[MAXPLAYERS +1]; // When was this user reported the last time? g_iLastReported[MAXPLAYERS +1]; // Whether or not a client saw the antispam message bool g_bSawMessage[MAXPLAYERS +1]; // Cookies Handle g_hLastReportCookie; Handle g_hLastReportedCookie; // Api Handle g_hOnReportPreForward; Handle g_hOnReportPostForward; Handle g_hOnDrawMenuForward; Handle g_hOnDrawOwnReasonForward; Handle g_hOnTrackerCountChangedForward; Handle g_hOnDrawTargetForward; Handle g_hOnAddToAdminCountForward; Handle g_hOnServerDataChangedForward; Handle g_hOnLogMessageForward; Handle g_hOnReportHandledForward; public Plugin myinfo = { name = "CallAdmin", author = "Impact, dordnung", description = "Call an Admin for help", version = CALLADMIN_VERSION, url = "http://gugyclan.eu" } public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max) { RegPluginLibrary("calladmin"); // Api CreateNative("CallAdmin_GetTrackersCount", Native_GetCurrentTrackers); CreateNative("CallAdmin_RequestTrackersCountRefresh", Native_RequestTrackersCountRefresh); CreateNative("CallAdmin_GetHostName", Native_GetHostName); CreateNative("CallAdmin_GetHostIP", Native_GetHostIP); CreateNative("CallAdmin_GetHostPort", Native_GetHostPort); CreateNative("CallAdmin_ReportClient", Native_ReportClient); CreateNative("CallAdmin_LogMessage", Native_LogMessage); CreateNative("CallAdmin_GetReportID", Native_GetReportID); return APLRes_Success; } public int Native_GetCurrentTrackers(Handle plugin, int numParams) { return g_iCurrentTrackers; } public int Native_RequestTrackersCountRefresh(Handle plugin, int numParams) { Timer_UpdateTrackersCount(null); } public int Native_GetHostName(Handle plugin, int numParams) { int max_size = GetNativeCell(2); SetNativeString(1, g_sServerName, max_size); } public int Native_GetHostIP(Handle plugin, int numParams) { int max_size = GetNativeCell(2); SetNativeString(1, g_sHostIP, max_size); } public int Native_GetHostPort(Handle plugin, int numParams) { return g_iHostPort; } public int Native_ReportClient(Handle plugin, int numParams) { int client; int target; char sReason[REASON_MAX_LENGTH]; client = GetNativeCell(1); target = GetNativeCell(2); GetNativeString(3, sReason, sizeof(sReason)); // We check for the REPORTER_CONSOLE define here, if this is set we have no valid client and the report comes from server if (!IsClientValid(client) && client != REPORTER_CONSOLE) { return false; } if (!IsClientValid(target)) { return false; } if (!Forward_OnReportPre(client, target, sReason)) { return false; } g_iCurrentReportID++; g_hActiveReports.Push(g_iCurrentReportID); Forward_OnReportPost(client, target, sReason); return true; } public int Native_LogMessage(Handle plugin, int numParams) { char sPluginName[64]; char sMessage[256]; GetPluginInfo(plugin, PlInfo_Name, sPluginName, sizeof(sPluginName)); FormatNativeString(0, 1, 2, sizeof(sMessage), _, sMessage); LogToFileEx(g_sLogFile, "[%s] %s", sPluginName, sMessage); Forward_OnLogMessage(plugin, sMessage); } public int Native_GetReportID(Handle plugin, int numParams) { return g_iCurrentReportID; } public void OnConfigsExecuted() { g_iHostPort = g_hHostPort.IntValue; UpdateHostIp(); g_hServerName.GetString(g_sServerName, sizeof(g_sServerName)); g_bPublicMessage = g_hPublicMessage.BoolValue; g_bOwnReason = g_hOwnReason.BoolValue; g_bConfirmCall = g_hConfirmCall.BoolValue; g_iSpamTime = g_hSpamTime.IntValue; g_iReportTime = g_hReportTime.IntValue; g_iAdminAction = g_hAdminAction.IntValue; g_fAdvertInterval = g_hAdvertInterval.FloatValue; delete g_hAdvertTimer; if (g_fAdvertInterval != 0.0) { g_hAdvertTimer = CreateTimer(g_fAdvertInterval, Timer_Advert, _, TIMER_REPEAT); } } public void OnPluginStart() { BuildPath(Path_SM, g_sLogFile, sizeof(g_sLogFile), "logs/calladmin.log"); g_hHostPort = FindConVar("hostport"); g_hHostIP = FindConVar("hostip"); g_hServerName = FindConVar("hostname"); if (g_hHostPort == null) { CallAdmin_LogMessage("Couldn't find cvar 'hostport'"); SetFailState("Couldn't find cvar 'hostport'"); } if (g_hHostIP == null) { CallAdmin_LogMessage("Couldn't find cvar 'hostip'"); SetFailState("Couldn't find cvar 'hostip'"); } if (g_hServerName == null) { CallAdmin_LogMessage("Couldn't find cvar 'hostname'"); SetFailState("Couldn't find cvar 'hostname'"); } RegConsoleCmd("sm_call", Command_Call); RegConsoleCmd("sm_calladmin", Command_Call); RegConsoleCmd("sm_call_handle", Command_HandleCall); RegConsoleCmd("sm_calladmin_handle", Command_HandleCall); RegConsoleCmd("sm_calladmin_reload", Command_Reload); AutoExecConfig_SetFile("plugin.calladmin"); g_hVersion = AutoExecConfig_CreateConVar("sm_calladmin_version", CALLADMIN_VERSION, "Plugin version", FCVAR_NOTIFY|FCVAR_DONTRECORD); g_hAdvertInterval = AutoExecConfig_CreateConVar("sm_calladmin_advert_interval", "60.0", "Interval to advert the use of calladmin, 0.0 deactivates the feature", FCVAR_NONE, true, 0.0, true, 1800.0); g_hPublicMessage = AutoExecConfig_CreateConVar("sm_calladmin_public_message", "0", "Whether or not a report should be notified to all players or only the reporter.", FCVAR_NONE, true, 0.0, true, 1.0); g_hOwnReason = AutoExecConfig_CreateConVar("sm_calladmin_own_reason", "1", "Whether or not a client can submit their own reason.", FCVAR_NONE, true, 0.0, true, 1.0); g_hConfirmCall = AutoExecConfig_CreateConVar("sm_calladmin_confirm_call", "1", "Whether or not a call must be confirmed by the client", FCVAR_NONE, true, 0.0, true, 1.0); g_hSpamTime = AutoExecConfig_CreateConVar("sm_calladmin_spamtime", "25", "An user must wait this many seconds after a report before he can issue a new one", FCVAR_NONE, true, 0.0); g_hReportTime = AutoExecConfig_CreateConVar("sm_calladmin_reporttime", "300", "An user cannot be reported again for this many seconds", FCVAR_NONE, true, 0.0); g_hAdminAction = AutoExecConfig_CreateConVar("sm_calladmin_admin_action", "0", "What happens when admins are in-game on report: 0 - Do nothing, let the report pass, 1 - Block the report and notify the caller and admins in-game about it", FCVAR_NONE, true, 0.0, true, 1.0); AutoExecConfig(true, "plugin.CallAdmin"); AutoExecConfig_CleanFile(); LoadTranslations("calladmin.phrases"); // This is done so that when the plugin is updated its version stays up to date too g_hVersion.SetString(CALLADMIN_VERSION, false, false); g_hVersion.AddChangeHook(OnCvarChanged); g_hServerName.AddChangeHook(OnCvarChanged); g_hHostPort.AddChangeHook(OnCvarChanged); g_hHostIP.AddChangeHook(OnCvarChanged); g_hAdvertInterval.AddChangeHook(OnCvarChanged); g_hPublicMessage.AddChangeHook(OnCvarChanged); g_hOwnReason.AddChangeHook(OnCvarChanged); g_hConfirmCall.AddChangeHook(OnCvarChanged); g_hSpamTime.AddChangeHook(OnCvarChanged); g_hReportTime.AddChangeHook(OnCvarChanged); g_hAdminAction.AddChangeHook(OnCvarChanged); // Modules must create their own updaters CreateTimer(10.0, Timer_UpdateTrackersCount, _, TIMER_REPEAT); // Used to allow a client to input their own reason AddCommandListener(ChatListener, "say"); AddCommandListener(ChatListener, "say2"); AddCommandListener(ChatListener, "say_team"); // Api g_hOnReportPreForward = CreateGlobalForward("CallAdmin_OnReportPre", ET_Event, Param_Cell, Param_Cell, Param_String); g_hOnReportPostForward = CreateGlobalForward("CallAdmin_OnReportPost", ET_Ignore, Param_Cell, Param_Cell, Param_String); g_hOnDrawMenuForward = CreateGlobalForward("CallAdmin_OnDrawMenu", ET_Event, Param_Cell); g_hOnDrawOwnReasonForward = CreateGlobalForward("CallAdmin_OnDrawOwnReason", ET_Event, Param_Cell); g_hOnTrackerCountChangedForward = CreateGlobalForward("CallAdmin_OnTrackerCountChanged", ET_Ignore, Param_Cell, Param_Cell); g_hOnDrawTargetForward = CreateGlobalForward("CallAdmin_OnDrawTarget", ET_Event, Param_Cell, Param_Cell); g_hOnAddToAdminCountForward = CreateGlobalForward("CallAdmin_OnAddToAdminCount", ET_Event, Param_Cell); g_hOnServerDataChangedForward = CreateGlobalForward("CallAdmin_OnServerDataChanged", ET_Ignore, Param_Cell, Param_Cell, Param_String, Param_String); g_hOnLogMessageForward = CreateGlobalForward("CallAdmin_OnLogMessage", ET_Ignore, Param_Cell, Param_String); g_hOnReportHandledForward = CreateGlobalForward("CallAdmin_OnReportHandled", ET_Ignore, Param_Cell, Param_Cell); // Cookies if (LibraryExists("clientprefs")) { g_hLastReportCookie = RegClientCookie("CallAdmin_LastReport", "Contains a timestamp when this user has reported the last time", CookieAccess_Private); g_hLastReportedCookie = RegClientCookie("CallAdmin_LastReported", "Contains a timestamp when this user was reported the last time", CookieAccess_Private); FetchClientCookies(); } // Report handling g_hActiveReports = new ArrayList(); // Reason handling g_hReasonAdt = new ArrayList(ByteCountToCells(REASON_MAX_LENGTH)); BuildPath(Path_SM, g_sReasonConfigFile, sizeof(g_sReasonConfigFile), "configs/calladmin_reasons.cfg"); if (!FileExists(g_sReasonConfigFile)) { CreateReasonList(); } ParseReasonList(); } void CreateReasonList() { File hFile; hFile = OpenFile(g_sReasonConfigFile, "w"); if (hFile == null) { CallAdmin_LogMessage("Failed to open configfile 'calladmin_reasons.cfg' for writing"); SetFailState("Failed to open configfile 'calladmin_reasons.cfg' for writing"); } hFile.WriteLine("// List of reasons seperated by a new line, max %d in length", REASON_MAX_LENGTH); hFile.WriteLine("Aimbot"); hFile.WriteLine("Wallhack"); hFile.WriteLine("Speedhack"); hFile.WriteLine("Spinhack"); hFile.WriteLine("Multihack"); hFile.WriteLine("No-Recoil Hack"); hFile.WriteLine("Other"); hFile.Close(); } void ParseReasonList() { File hFile; hFile = OpenFile(g_sReasonConfigFile, "r"); if (hFile == null) { CallAdmin_LogMessage("Failed to open configfile 'calladmin_reasons.cfg' for reading"); SetFailState("Failed to open configfile 'calladmin_reasons.cfg' for reading"); } // Buffer must be a little bit bigger to have enough room for possible comments and being able to check for too long reasons char sReadBuffer[PLATFORM_MAX_PATH]; int len; while (!hFile.EndOfFile() && hFile.ReadLine(sReadBuffer, sizeof(sReadBuffer))) { if (sReadBuffer[0] == '/' || IsCharSpace(sReadBuffer[0])) { continue; } ReplaceString(sReadBuffer, sizeof(sReadBuffer), "\n", ""); ReplaceString(sReadBuffer, sizeof(sReadBuffer), "\r", ""); ReplaceString(sReadBuffer, sizeof(sReadBuffer), "\t", ""); len = strlen(sReadBuffer); if (len < 3 || len > REASON_MAX_LENGTH) { continue; } // Add the reason to the list only if it doesn't already exist if (g_hReasonAdt.FindString(sReadBuffer) == -1) { g_hReasonAdt.PushString(sReadBuffer); } } hFile.Close(); } public void OnClientCookiesCached(int client) { char sCookieBuf[24]; GetClientCookie(client, g_hLastReportCookie, sCookieBuf, sizeof(sCookieBuf)); if (strlen(sCookieBuf) > 0) { g_iLastReport[client] = StringToInt(sCookieBuf); } // Just to be safe sCookieBuf[0] = '\0'; GetClientCookie(client, g_hLastReportedCookie, sCookieBuf, sizeof(sCookieBuf)); if (strlen(sCookieBuf) > 0) { g_iLastReported[client] = StringToInt(sCookieBuf); } } void FetchClientCookies() { for (int i; i <= MaxClients; i++) { if (IsClientValid(i) && !IsFakeClient(i) && !IsClientSourceTV(i) && !IsClientReplay(i) && AreClientCookiesCached(i)) { OnClientCookiesCached(i); } } } bool Forward_OnDrawMenu(int client) { Action result; Call_StartForward(g_hOnDrawMenuForward); Call_PushCell(client); Call_Finish(result); return (result == Plugin_Continue); } bool Forward_OnReportPre(int client, int target, const char[] reason) { Action result; Call_StartForward(g_hOnReportPreForward); Call_PushCell(client); Call_PushCell(target); Call_PushString(reason); Call_Finish(result); return (result == Plugin_Continue); } void Forward_OnReportPost(int client, int target, const char[] reason) { Call_StartForward(g_hOnReportPostForward); Call_PushCell(client); Call_PushCell(target); Call_PushString(reason); Call_Finish(); } bool Forward_OnDrawOwnReason(int client) { Action result; Call_StartForward(g_hOnDrawOwnReasonForward); Call_PushCell(client); Call_Finish(result); return (result == Plugin_Continue); } bool Forward_OnAddToAdminCount(int client) { Action result; Call_StartForward(g_hOnAddToAdminCountForward); Call_PushCell(client); Call_Finish(result); return (result == Plugin_Continue); } void Forward_OnTrackerCountChanged(int oldVal, int newVal) { Call_StartForward(g_hOnTrackerCountChangedForward); Call_PushCell(oldVal); Call_PushCell(newVal); Call_Finish(); } bool Forward_OnDrawTarget(int client, int target) { Action result; Call_StartForward(g_hOnDrawTargetForward); Call_PushCell(client); Call_PushCell(target); Call_Finish(result); return (result == Plugin_Continue); } void Forward_OnServerDataChanged(ConVar convar, ServerData type, const char[] oldVal, const char[] newVal) { Call_StartForward(g_hOnServerDataChangedForward); Call_PushCell(convar); Call_PushCell(type); Call_PushString(oldVal); Call_PushString(newVal); Call_Finish(); } void Forward_OnLogMessage(Handle plugin, const char[] message) { Call_StartForward(g_hOnLogMessageForward); Call_PushCell(plugin); Call_PushString(message); Call_Finish(); } void Forward_OnReportHandled(int client, int id) { Call_StartForward(g_hOnReportHandledForward); Call_PushCell(client); Call_PushCell(id); Call_Finish(); } public Action Timer_Advert(Handle timer) { if (g_iCurrentTrackers > 0) { // Spelling is different (0 admins, 1 admin, 2 admins, 3 admins...) if (g_iCurrentTrackers == 1) { PrintToChatAll("\x04[CALLADMIN]\x03 %t", "CallAdmin_AdvertMessageSingular", g_iCurrentTrackers); } else { PrintToChatAll("\x04[CALLADMIN]\x03 %t", "CallAdmin_AdvertMessagePlural", g_iCurrentTrackers); } } return Plugin_Handled; } public void OnCvarChanged(ConVar cvar, const char[] oldValue, const char[] newValue) { if (cvar == g_hHostPort) { g_iHostPort = g_hHostPort.IntValue; Forward_OnServerDataChanged(cvar, ServerData_HostPort, oldValue, newValue); } else if (cvar == g_hHostIP) { UpdateHostIp(); Forward_OnServerDataChanged(cvar, ServerData_HostIP, g_sHostIP, g_sHostIP); } else if (cvar == g_hServerName) { g_hServerName.GetString(g_sServerName, sizeof(g_sServerName)); Forward_OnServerDataChanged(cvar, ServerData_HostName, oldValue, newValue); } else if (cvar == g_hVersion) { g_hVersion.SetString(CALLADMIN_VERSION, false, false); } else if (cvar == g_hAdvertInterval) { delete g_hAdvertTimer; g_fAdvertInterval = g_hAdvertInterval.FloatValue; if (g_fAdvertInterval != 0.0) { g_hAdvertTimer = CreateTimer(g_fAdvertInterval, Timer_Advert, _, TIMER_REPEAT); } } else if (cvar == g_hPublicMessage) { g_bPublicMessage = g_hPublicMessage.BoolValue; } else if (cvar == g_hOwnReason) { g_bOwnReason = g_hOwnReason.BoolValue; } else if (cvar == g_hConfirmCall) { g_bConfirmCall = g_hConfirmCall.BoolValue; } else if (cvar == g_hSpamTime) { g_iSpamTime = g_hSpamTime.IntValue; } else if (cvar == g_hReportTime) { g_iReportTime = g_hReportTime.IntValue; } else if (cvar == g_hAdminAction) { g_iAdminAction = g_hAdminAction.IntValue; } } public Action Command_Call(int client, int argc) { // Console cannot use this if (client == 0) { ReplyToCommand(client, "This command can't be used from console"); return Plugin_Handled; } if (!Forward_OnDrawMenu(client)) { return Plugin_Handled; } if (g_iLastReport[client] == 0 || LastReportTimeCheck(client)) { g_bSawMessage[client] = false; ShowClientSelectMenu(client); } else if (!g_bSawMessage[client]) { ReplyToCommand(client, "\x04[CALLADMIN]\x03 %t", "CallAdmin_CommandNotAllowed", g_iSpamTime - ( GetTime() - g_iLastReport[client] )); g_bSawMessage[client] = true; } return Plugin_Handled; } public Action Command_HandleCall(int client, int argc) { if (client == 0) { ReplyToCommand(client, "This command can't be used from console"); return Plugin_Handled; } if (!CheckCommandAccess(client, "sm_calladmin_admin", ADMFLAG_BAN, false)) { ReplyToCommand(client, "\x04[CALLADMIN]\x03 %t", "CallAdmin_NoAdmin"); return Plugin_Handled; } if (argc != 1) { char cmdName[64]; GetCmdArg(0, cmdName, sizeof(cmdName)); ReplyToCommand(client, "\x04[CALLADMIN]\x03 %t: %s ", "CallAdmin_WrongNumberOfArguments", cmdName); return Plugin_Handled; } char sArgID[10]; int reportID; GetCmdArg(1, sArgID, sizeof(sArgID)); reportID = StringToInt(sArgID); if (reportID > g_iCurrentReportID) { ReplyToCommand(client, "\x04[CALLADMIN]\x03 %t", "CallAdmin_WrongReportID"); return Plugin_Handled; } // Report was already handled int reportIndex = g_hActiveReports.FindValue(reportID); if (reportIndex == -1) { ReplyToCommand(client, "\x04[CALLADMIN]\x03 %t", "CallAdmin_ReportAlreadyHandled"); return Plugin_Handled; } g_hActiveReports.Erase(reportIndex); Forward_OnReportHandled(client, reportID); return Plugin_Handled; } public Action Command_Reload(int client, int argc) { if (!CheckCommandAccess(client, "sm_calladmin_admin", ADMFLAG_BAN, false)) { ReplyToCommand(client, "\x04[CALLADMIN]\x03 %t", "CallAdmin_NoAdmin"); return Plugin_Handled; } g_hActiveReports.Clear(); g_hReasonAdt.Clear(); ParseReasonList(); return Plugin_Handled; } bool LastReportTimeCheck(int client) { if (g_iLastReport[client] <= ( GetTime() - g_iSpamTime )) { return true; } return false; } bool LastReportedTimeCheck(int client) { if (g_iLastReported[client] <= ( GetTime() - g_iReportTime )) { return true; } return false; } // Updates the timestamps of lastreport and lastreported void SetStates(int client, int target) { int currentTime = GetTime(); g_iLastReport[client] = currentTime; g_iLastReported[target] = currentTime; // Cookies if (LibraryExists("clientprefs")) { SetClientCookieEx(client, g_hLastReportCookie, "%d", currentTime); SetClientCookieEx(target, g_hLastReportedCookie, "%d", currentTime); } } void ConfirmCall(int client) { Menu menu = new Menu(MenuHandler_ConfirmCall); menu.SetTitle("%T", "CallAdmin_ConfirmCall", client); char sConfirm[24]; Format(sConfirm, sizeof(sConfirm), "%T", "CallAdmin_Yes", client); menu.AddItem("Yes", sConfirm); Format(sConfirm, sizeof(sConfirm), "%T", "CallAdmin_No", client); menu.AddItem("No", sConfirm); menu.Display(client, 30); } public int MenuHandler_ConfirmCall(Menu menu, MenuAction action, int client, int param2) { if (action == MenuAction_Select) { char sInfo[24]; menu.GetItem(param2, sInfo, sizeof(sInfo)); // Client has chosen to confirm the call if (StrEqual("Yes", sInfo)) { if (!ReportPlayer(client, g_iTarget[client], g_sTargetReason[client])) { return; } } else { PrintToChat(client, "\x04[CALLADMIN]\x03 %t", "CallAdmin_CallAborted"); } } else if (action == MenuAction_End) { menu.Close(); } } bool PreReportCheck(int client, int target) { // Selected target isn't valid anymore if (!IsClientValid(target)) { PrintToChat(client, "\x04[CALLADMIN]\x03 %t", "CallAdmin_NotInGame"); return false; } // Already reported (race condition) if (!LastReportedTimeCheck(target)) { PrintToChat(client, "\x04[CALLADMIN]\x03 %t", "CallAdmin_AlreadyReported"); return false; } return true; } bool ReportPlayer(int client, int target, char[] sReason) { if (!PreReportCheck(client, target)) { return false; } // Admins available and we want to notify them instead of sending the report if (GetAdminCount() > 0 && g_iAdminAction == ADMIN_ACTION_BLOCK_MESSAGE) { PrintToChat(client, "\x04[CALLADMIN]\x03 %t", "CallAdmin_IngameAdminNotified"); PrintNotifyMessageToAdmins(client, g_iTarget[client]); SetStates(client, g_iTarget[client]); return false; } if (!Forward_OnReportPre(client, g_iTarget[client], g_sTargetReason[client])) { return false; } if (g_bPublicMessage) { PrintToChatAll("\x04[CALLADMIN]\x03 %t", "CallAdmin_HasReported", client, target, sReason); } else { PrintToChat(client, "\x04[CALLADMIN]\x03 %t", "CallAdmin_YouHaveReported", target, sReason); } SetStates(client, target); g_iCurrentReportID++; g_hActiveReports.Push(g_iCurrentReportID); Forward_OnReportPost(client, target, sReason); return true; } public Action Timer_UpdateTrackersCount(Handle timer) { int temp = GetTotalTrackers(); if (temp != g_iCurrentTrackers) { Forward_OnTrackerCountChanged(g_iCurrentTrackers, temp); } g_iCurrentTrackers = temp; return Plugin_Continue; } int GetTotalTrackers() { Handle hIter; Handle hPlugin; Function func; int count; int tempcount; hIter = GetPluginIterator(); while (MorePlugins(hIter)) { hPlugin = ReadPlugin(hIter); if (GetPluginStatus(hPlugin) == Plugin_Running) { // We check if the plugin has the public CallAdmin_OnRequestTrackersCountRefresh function if ( (func = GetFunctionByName(hPlugin, "CallAdmin_OnRequestTrackersCountRefresh") ) != INVALID_FUNCTION) { Call_StartFunction(hPlugin, func); Call_PushCellRef(tempcount); Call_Finish(); if (tempcount > 0) { count += tempcount; } } } } delete hIter; return count; } void ShowClientSelectMenu(int client) { char sName[MAX_NAME_LENGTH]; char sID[24]; Menu menu = new Menu(MenuHandler_ClientSelect); menu.SetTitle("%T", "CallAdmin_SelectClient", client); for (int i; i <= MaxClients; i++) { if (i != client && LastReportedTimeCheck(i) && IsClientValid(i) && !IsFakeClient(i) && !IsClientSourceTV(i) && !IsClientReplay(i) && Forward_OnDrawTarget(client, i)) { GetClientName(i, sName, sizeof(sName)); Format(sID, sizeof(sID), "%d", GetClientSerial(i)); menu.AddItem(sID, sName); } } // Menu has no items, no players to report if (menu.ItemCount < 1) { PrintToChat(client, "\x04[CALLADMIN]\x03 %t", "CallAdmin_NoPlayers"); } else { menu.Display(client, 30); } } public int MenuHandler_ClientSelect(Menu menu, MenuAction action, int client, int param2) { if (action == MenuAction_Select) { char sInfo[24]; int iSerial; int iID; menu.GetItem(param2, sInfo, sizeof(sInfo)); iSerial = StringToInt(sInfo); iID = GetClientFromSerial(iSerial); if (!PreReportCheck(client, iID)) { return; } g_iTarget[client] = iID; ShowBanReasonMenu(client); } else if (action == MenuAction_End) { menu.Close(); } } public void OnClientDisconnect_Post(int client) { g_iTarget[client] = 0; g_sTargetReason[client][0] = '\0'; g_iLastReport[client] = 0; g_iLastReported[client] = 0; g_bSawMessage[client] = false; g_bAwaitingReason[client] = false; RemoveAsTarget(client); } void RemoveAsTarget(int client) { for (int i; i <= MaxClients; i++) { if (g_iTarget[i] == client) { g_iTarget[i] = 0; } } } void ShowBanReasonMenu(int client) { int count; char sReasonBuffer[REASON_MAX_LENGTH]; count = g_hReasonAdt.Length; Menu menu = new Menu(MenuHandler_BanReason); menu.SetTitle("%T", "CallAdmin_SelectReason", client, g_iTarget[client]); for (int i; i < count; i++) { g_hReasonAdt.GetString(i, sReasonBuffer, sizeof(sReasonBuffer)); if (strlen(sReasonBuffer) < 3) { continue; } menu.AddItem(sReasonBuffer, sReasonBuffer); } // Own reason, call the forward if (g_bOwnReason && Forward_OnDrawOwnReason(client)) { char sOwnReason[REASON_MAX_LENGTH]; Format(sOwnReason, sizeof(sOwnReason), "%T", "CallAdmin_OwnReason", client); menu.AddItem("Own reason", sOwnReason); } menu.Display(client, 30); } public int MenuHandler_BanReason(Menu menu, MenuAction action, int client, int param2) { if (action == MenuAction_Select) { char sInfo[REASON_MAX_LENGTH]; menu.GetItem(param2, sInfo, sizeof(sInfo)); // User has chosen to use his own reason if (StrEqual("Own reason", sInfo)) { g_bAwaitingReason[client] = true; PrintToChat(client, "\x04[CALLADMIN]\x03 %t", "CallAdmin_TypeOwnReason"); return; } Format(g_sTargetReason[client], sizeof(g_sTargetReason[]), sInfo); if (!PreReportCheck(client, g_iTarget[client])) { return; } if (g_bConfirmCall) { ConfirmCall(client); } else { if (!ReportPlayer(client, g_iTarget[client], g_sTargetReason[client])) { return; } } } else if (action == MenuAction_End) { menu.Close(); } } public Action ChatListener(int client, const char[] command, int argc) { // There were a few cases were the client index was invalid which caused an index out-of-bounds error // Invalid clients shouldn't be able to trigger this callback so the reason why this happens has yet to be found out // Until then we have this check here to prevent it if (!IsClientValid(client)) { return Plugin_Continue; } if (g_bAwaitingReason[client] && !IsChatTrigger()) { // 2 more for quotes char sReason[REASON_MAX_LENGTH + 2]; GetCmdArgString(sReason, sizeof(sReason)); StripQuotes(sReason); strcopy(g_sTargetReason[client], sizeof(g_sTargetReason[]), sReason); g_bAwaitingReason[client] = false; // Has aborted if (StrEqual(sReason, "!noreason") || StrEqual(sReason, "!abort")) { PrintToChat(client, "\x04[CALLADMIN]\x03 %t", "CallAdmin_CallAborted"); return Plugin_Handled; } // Reason was too short if (strlen(sReason) < 3) { g_bAwaitingReason[client] = true; PrintToChat(client, "\x04[CALLADMIN]\x03 %t", "CallAdmin_OwnReasonTooShort"); return Plugin_Handled; } if (!PreReportCheck(client, g_iTarget[client])) { return Plugin_Handled; } if (g_bConfirmCall) { ConfirmCall(client); } else { if (!ReportPlayer(client, g_iTarget[client], g_sTargetReason[client])) { return Plugin_Handled; } } // Block the chatmessage return Plugin_Handled; } return Plugin_Continue; } stock int GetRealClientCount() { int count; for (int i; i <= MaxClients; i++) { if (IsClientValid(i) && !IsFakeClient(i) && !IsClientSourceTV(i) && !IsClientReplay(i)) { count++; } } return count; } stock int GetAdminCount() { int count; for (int i; i <= MaxClients; i++) { if (IsClientValid(i) && !IsFakeClient(i) && !IsClientSourceTV(i) && !IsClientReplay(i) && CheckCommandAccess(i, "sm_calladmin_admin", ADMFLAG_BAN, false) && Forward_OnAddToAdminCount(i)) { count++; } } return count; } stock void PrintNotifyMessageToAdmins(int client, int target) { for (int i; i <= MaxClients; i++) { if (IsClientValid(i) && !IsFakeClient(i) && !IsClientSourceTV(i) && !IsClientReplay(i) && CheckCommandAccess(i, "sm_calladmin_admin", ADMFLAG_BAN, false) && Forward_OnAddToAdminCount(i)) { PrintToChat(i, "\x04[CALLADMIN]\x03 %t", "CallAdmin_AdminNotification", client, target, g_sTargetReason[client]); } } } stock void LongToIp(int long, char[] str, int maxlen) { int pieces[4]; pieces[0] = ((long >>> 24) & 255); pieces[1] = ((long >>> 16) & 255); pieces[2] = ((long >>> 8) & 255); pieces[3] = (long & 255); Format(str, maxlen, "%d.%d.%d.%d", pieces[0], pieces[1], pieces[2], pieces[3]); } // Updates the global g_sHostIP variable to the current ip of the server // Using the int value directly provides incorrect results, when given the time it should be examined why void UpdateHostIp() { char tmpString[sizeof(g_sHostIP)]; g_hHostIP.GetString(tmpString, sizeof(tmpString)); int tmpInt = StringToInt(tmpString); LongToIp(tmpInt, g_sHostIP, sizeof(g_sHostIP)); } stock void SetClientCookieEx(int client, Handle cookie, const char[] format, any:...) { char sFormatBuf[1024]; VFormat(sFormatBuf, sizeof(sFormatBuf), format, 4); SetClientCookie(client, cookie, sFormatBuf); }