/* SLAG: Half-Life Banning System. Copyright Expade, 2015. All rights reserved. Features: MySQL database for storing banned AuthIDs. Automatic table creation. By default commands require 'm' access flag. Commands: slag_add [reason] - bans authid. slag_remove - unbans authid. slag_list [page] - shows list of banned authids. CVARs: slag_hostname "127.0.0.1" - host running MySQL. slag_username "root" - user name used to connect to MySQL. slag_password "" - password used to connect to MySQL. slag_database "SLAG" - database name to use. slag_immunity "ab" - if player has one of these access rights flags we allow him to enter without checking for a AuthID ban. ChangeLog: 1.00 [2014.09.07] Initial release. 1.10 [2014.11.30] ! Fixed: compatibility with AMXX v1.8.2 1.20 [2014.12.03] ! Fixed: small texts corrections. ! Fixed: small potential bugs. 1.30 [2014.12.07] + Added: support multiple servers using the same database. + Added: now store datetime AuthID was banned. + Recommended DB update: ALTER TABLE `SLAG` ADD COLUMN `Timestamp` TIMESTAMP(14) NOT NULL AFTER `Reason`; 1.40 [2015.02.21] + Recommended DB update: ALTER TABLE `SLAG` CHANGE COLUMN `Timestamp` `DateTimeBanned` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP; + Added: slag_list command. */ #pragma semicolon 1 #pragma ctrlchar '\' #include #include #include #define PROJECT "SLAG" #define VERSION "1.40" #define KEY_AUTHID "AuthID" #define KEY_REASON "Reason" #define KEY_DATETIME "DateTimeBanned" #define MAX_AUTHID_LENGTH 32 #define MAX_REASON_LENGTH 64 #define MAX_BUFFER_LENGTH 1024 #define DEF_ADMIN_LEVEL ADMIN_LEVEL_A #define SQL_CVARS_FLAGS FCVAR_EXTDLL #define TASK_CHECKID_BASE 768 #define CHECKID_DELAY 0.1 #define AUTHIDS_PER_PAGE 10 #if AMXX_VERSION_NUM < 183 new MaxClients; #endif enum _:TempData { _admin, _target, _authid[MAX_AUTHID_LENGTH], _reason[MAX_REASON_LENGTH] }; new pcvar_hostname; new pcvar_username; new pcvar_password; new pcvar_database; new pcvar_immunity; new Handle:SQL_Tracker; new NumRows; new CurrentPage; new TotalPages; public plugin_init() { register_plugin(PROJECT, VERSION, "Expade"); register_cvar("slag_version", VERSION, FCVAR_SERVER | FCVAR_SPONLY | FCVAR_UNLOGGED); register_dictionary("slag.txt"); pcvar_hostname = register_cvar("slag_hostname", "127.0.0.1", SQL_CVARS_FLAGS); pcvar_username = register_cvar("slag_username", "root", SQL_CVARS_FLAGS); pcvar_password = register_cvar("slag_password", "", SQL_CVARS_FLAGS); pcvar_database = register_cvar("slag_database", PROJECT, SQL_CVARS_FLAGS); pcvar_immunity = register_cvar("slag_immunity", "ab"); register_concmd("slag_add", "concmd_Add", DEF_ADMIN_LEVEL, " [reason] - bans authid"); register_concmd("slag_remove", "concmd_Remove", DEF_ADMIN_LEVEL, " - unbans authid"); register_concmd("slag_list", "concmd_List", DEF_ADMIN_LEVEL, "[page] - shows list of banned authids"); #if AMXX_VERSION_NUM < 183 MaxClients = get_maxplayers(); #endif set_task(0.5, "SQL_Init"); } public SQL_Init() { new hostname[64], username[32], password[32], database[128]; get_pcvar_string(pcvar_hostname, hostname, charsmax(hostname)); get_pcvar_string(pcvar_username, username, charsmax(username)); get_pcvar_string(pcvar_password, password, charsmax(password)); get_pcvar_string(pcvar_database, database, charsmax(database)); SQL_Tracker = SQL_MakeDbTuple(hostname, username, password, database); SQL_CreateTable("AfterCreateTable"); } public AfterCreateTable(failstate, Handle:buffer, const error[], errorcode) { if (failstate) { SQL_ThreadError(0, failstate, error, errorcode); return; } SQL_CountRows("AfterCountRows"); } public AfterCountRows(failstate, Handle:buffer, const error[], errorcode) { if (failstate) { SQL_ThreadError(0, failstate, error, errorcode); return; } NumRows = SQL_ReadResult(buffer, 0); } public plugin_end() { if (SQL_Tracker != Handle:0) { SQL_FreeHandle(SQL_Tracker); } } public client_authorized(id) { if (NumRows && !is_user_bot(id) && !is_user_hltv(id) && !user_has_immunity(id)) { set_task(CHECKID_DELAY, "CheckID", id + TASK_CHECKID_BASE); } } public CheckID(id) { id -= TASK_CHECKID_BASE; new authid[MAX_AUTHID_LENGTH]; get_user_authid(id, authid, charsmax(authid)); new data[TempData]; data[_target] = id; copy(data[_authid], charsmax(data[_authid]), authid); SQL_SelectRows("AfterCheckID", data, sizeof(data), true, 1); } public AfterCheckID(failstate, Handle:buffer, const error[], errorcode, const data[], datasize) { if (failstate) { SQL_ThreadError(0, failstate, error, errorcode); return; } if (SQL_NumResults(buffer)) { SQL_ReadResult(buffer, SQL_FieldNameToNum(buffer, KEY_REASON), data[_reason], charsmax(data[_reason])); server_cmd("kick #%i \"%s\"", get_user_userid(data[_target]), data[_reason]); } } public concmd_Add(id, level, cid) { if (!cmd_access(id, level, cid, 2)) { return PLUGIN_HANDLED; } new authid[MAX_AUTHID_LENGTH], reason[MAX_REASON_LENGTH]; read_argv(1, authid, charsmax(authid)); read_argv(2, reason, charsmax(reason)); if (!reason[0]) { formatex(reason, charsmax(reason), "%L", LANG_SERVER, "SLAG_MSG_01"); } new data[TempData]; data[_admin] = id; data[_target] = find_player("c", authid); copy(data[_authid], charsmax(data[_authid]), authid); copy(data[_reason], charsmax(data[_reason]), reason); SQL_Insert("AfterInsertAuthID", data, sizeof(data)); return PLUGIN_HANDLED; } public AfterInsertAuthID(failstate, Handle:buffer, const error[], errorcode, const data[], datasize, Float:delay) { new id = data[_admin]; if (failstate) { SQL_ThreadError(id, failstate, error, errorcode); return; } if (SQL_AffectedRows(buffer)) { new target = data[_target]; console_print(id, "[%s] %L", PROJECT, id, "SLAG_MSG_02", data[_authid], delay); NumRows += 1; if (!is_user_bot(target) && !is_user_hltv(target) && !user_has_immunity(target)) { server_cmd("kick #%i \"%s\"", get_user_userid(target), data[_reason]); } } else { console_print(id, "[%s] %L", PROJECT, id, "SLAG_MSG_03"); } } public concmd_Remove(id, level, cid) { if (!cmd_access(id, level, cid, 2)) { return PLUGIN_HANDLED; } new authid[MAX_AUTHID_LENGTH]; read_argv(1, authid, charsmax(authid)); new data[TempData]; data[_admin] = id; copy(data[_authid], charsmax(data[_authid]), authid); SQL_Delete("AfterDeleteAuthID", data, sizeof(data)); return PLUGIN_HANDLED; } public AfterDeleteAuthID(failstate, Handle:buffer, const error[], errorcode, const data[], datasize, Float:delay) { new id = data[_admin]; if (failstate) { SQL_ThreadError(id, failstate, error, errorcode); return; } if (SQL_AffectedRows(buffer)) { console_print(id, "[%s] %L", PROJECT, id, "SLAG_MSG_04", data[_authid], delay); if (NumRows) NumRows -= 1; } else { console_print(id, "[%s] %L", PROJECT, id, "SLAG_MSG_05"); } } public concmd_List(id, level, cid) { if (!cmd_access(id, level, cid, 1)) { return PLUGIN_HANDLED; } if (!NumRows) { console_print(id, "[%s] %L", PROJECT, id, "SLAG_MSG_06"); return PLUGIN_HANDLED; } CurrentPage = 1; TotalPages = floatround(float(NumRows) / float(AUTHIDS_PER_PAGE), floatround_ceil); if (read_argc() > 1) { new page[8]; read_argv(1, page, charsmax(page)); CurrentPage = str_to_num(page); if (CurrentPage < 1) CurrentPage = 1; if (CurrentPage > TotalPages) CurrentPage = TotalPages; } new data[TempData], limit = (CurrentPage - 1) * AUTHIDS_PER_PAGE; data[_admin] = id; SQL_SelectRows("AfterShowBannedAuthIDs", data, sizeof(data), false, limit); return PLUGIN_HANDLED; } public AfterShowBannedAuthIDs(failstate, Handle:buffer, const error[], errorcode, const data[], datasize) { new id = data[_admin]; if (failstate) { SQL_ThreadError(id, failstate, error, errorcode); return; } while (SQL_MoreResults(buffer)) { SQL_ReadResult(buffer, SQL_FieldNameToNum(buffer, KEY_AUTHID), data[_authid], charsmax(data[_authid])); console_print(id, data[_authid]); SQL_NextRow(buffer); } if (CurrentPage < TotalPages) { console_print(id, "[%s] %L", PROJECT, id, "SLAG_MSG_07", CurrentPage + 1); } else { console_print(id, "[%s] %L", PROJECT, id, "SLAG_MSG_08"); } } stock SQL_CreateTable(const handler[]) { new buffer[MAX_BUFFER_LENGTH]; formatex(buffer, charsmax(buffer), "CREATE TABLE IF NOT EXISTS `%s` (`%s` VARCHAR(%i) NOT NULL, `%s` VARCHAR(%i) NOT NULL, `%s` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`%s`));", PROJECT, KEY_AUTHID, MAX_AUTHID_LENGTH, KEY_REASON, MAX_REASON_LENGTH, KEY_DATETIME, KEY_AUTHID); SQL_ThreadQuery(SQL_Tracker, handler, buffer); } stock SQL_CountRows(const handler[]) { new buffer[MAX_BUFFER_LENGTH]; formatex(buffer, charsmax(buffer), "SELECT COUNT(`%s`) FROM `%s`;", KEY_AUTHID, PROJECT); SQL_ThreadQuery(SQL_Tracker, handler, buffer); } stock SQL_SelectRows(const handler[], const data[], datasize, bool:checkexist, limit) { new buffer[MAX_BUFFER_LENGTH]; checkexist ? formatex(buffer, charsmax(buffer), "SELECT `%s` FROM `%s` WHERE `%s` = '%s' ORDER BY `%s` DESC LIMIT %u;", KEY_REASON, PROJECT, KEY_AUTHID, data[_authid], KEY_DATETIME, limit) : formatex(buffer, charsmax(buffer), "SELECT `%s` FROM `%s` ORDER BY `%s` ASC LIMIT %u, %u;", KEY_AUTHID, PROJECT, KEY_DATETIME, limit, AUTHIDS_PER_PAGE); SQL_ThreadQuery(SQL_Tracker, handler, buffer, data, datasize); } stock SQL_Insert(const handler[], const data[], datasize) { new buffer[MAX_BUFFER_LENGTH]; formatex(buffer, charsmax(buffer), "INSERT INTO `%s` (`%s`, `%s`) VALUES ('%s', '%s');", PROJECT, KEY_AUTHID, KEY_REASON, data[_authid], data[_reason]); SQL_ThreadQuery(SQL_Tracker, handler, buffer, data, datasize); } stock SQL_Delete(const handler[], const data[], datasize) { new buffer[MAX_BUFFER_LENGTH]; formatex(buffer, charsmax(buffer), "DELETE FROM `%s` WHERE `%s` = '%s';", PROJECT, KEY_AUTHID, data[_authid]); SQL_ThreadQuery(SQL_Tracker, handler, buffer, data, datasize); } stock SQL_ThreadError(index, failstate, const error[], errorcode) { switch (failstate) { case TQUERY_CONNECT_FAILED: console_print(index, "[%s] %L", PROJECT, index, "SLAG_ERR_01"); case TQUERY_QUERY_FAILED: console_print(index, "[%s] %L", PROJECT, index, "SLAG_ERR_02"); case TQUERY_SUCCESS: return; } console_print(index, "[%s] %L", PROJECT, index, "SLAG_ERR_03", errorcode); console_print(index, "[%s] %s", PROJECT, error); } stock user_has_immunity(index) { if (index < 1 || index > MaxClients) { return -1; } static flags[27], bitmask; get_pcvar_string(pcvar_immunity, flags, charsmax(flags)); for (new i = 0; flags[i]; i++) { if ('a' <= flags[i] <= 'z') { bitmask |= 1 << (flags[i] - 'a'); } } return (get_user_flags(index) & bitmask); }