diff --git a/plugins/globalbans.smx b/plugins/globalbans.smx index 7858097..8147a87 100644 Binary files a/plugins/globalbans.smx and b/plugins/globalbans.smx differ diff --git a/scripting/globalbans.sp b/scripting/globalbans.sp index 4bbd37e..19a6222 100644 --- a/scripting/globalbans.sp +++ b/scripting/globalbans.sp @@ -5,6 +5,10 @@ #define PLUGIN_VERSION "1.0" #define DB_NAME "globalbans" +#define BANFLAG_NONE 0 +#define BANFLAG_IPBANNED 1 +#define BANFLAG_SUSPENDED 2 + #include #include #include @@ -20,6 +24,10 @@ public Plugin myinfo = static Database g_db; static ConVar hKickType; +static StringMap pendingInsertQueries; + +static int iPendingCounter; + public void OnPluginStart() { if(!SQL_CheckConfig(DB_NAME)) { @@ -29,6 +37,8 @@ public void OnPluginStart() { SetFailState("Failed to connect to database."); } + pendingInsertQueries = new StringMap(); + hKickType = CreateConVar("sm_globalbans_kick_type", "1", "0 = Do not kick, just notify\n1 = Kick if banned\n 2 = Kick if cannot reach database", FCVAR_NONE, true, 0.0, true, 2.0); } @@ -62,7 +72,7 @@ public void OnClientAuthorized(int client, const char[] auth) { if(!StrEqual(auth, "BOT", true)) { static char query[256], ip[32]; GetClientIP(client, ip, sizeof(ip)); - g_db.Format(query, sizeof(query), "SELECT `reason`, `steamid`, `expired` FROM `bans` WHERE `steamid` LIKE 'STEAM_%%:%%:%s' OR ip = '%s'", auth[10], ip); + g_db.Format(query, sizeof(query), "SELECT `reason`, `steamid`, `expired`, `public_message`, `flags`, `id` FROM `bans` WHERE `expired` = 0 AND `steamid` LIKE 'STEAM_%%:%%:%s' OR ip = '%s'", auth[10], ip); g_db.Query(DB_OnConnectCheck, query, GetClientUserId(client), DBPrio_High); } } @@ -76,28 +86,39 @@ public Action OnBanIdentity(const char[] identity, int time, int flags, const ch executor = "CONSOLE"; } static char query[255]; - static char expiresDate[64]; + + + // Setup expiration date + char expiresDate[64]; if(time > 0) { Format(expiresDate, sizeof(expiresDate), "%d", GetTime() + (time * 60000)); }else{ Format(expiresDate, sizeof(expiresDate), "NULL"); } + g_db.Format(query, sizeof(query), "INSERT INTO bans" - ..."(steamid, reason, expires, executor, ip_banned)" - ..."VALUES ('%s', '%s', %s, '%s', 0)", + ..."(steamid, reason, expires, executor, flags, timestamp)" + ..."VALUES ('%s', '%s', %s, '%s', %d, UNIX_TIMESTAMP)", identity, reason, expiresDate, - executor + executor, + BANFLAG_NONE ); - g_db.Query(DB_OnBanQuery, query); + static char strKey[8]; + int key = ++iPendingCounter; + IntToString(key, strKey, sizeof(strKey)); + pendingInsertQueries.SetString(strKey, query); + + g_db.Format(query, sizeof(query), "SELECT `flags` FROM `bans` WHERE `expired` = 0 AND `steamid` LIKE 'STEAM_%%:%%:%s' OR ip = '%s'", identity[10], identity); + g_db.Query(DB_OnBanPreCheck, query, key); + }else if(flags == BANFLAG_IP) { LogMessage("Cannot save IP without steamid: %s [Source: %s]", identity, source); } return Plugin_Continue; } - public Action OnBanClient(int client, int time, int flags, const char[] reason, const char[] kick_message, const char[] command, any source) { char executor[32], identity[32], ip[32]; GetClientAuthId(client, AuthId_Steam2, identity, sizeof(identity)); @@ -115,7 +136,8 @@ public Action OnBanClient(int client, int time, int flags, const char[] reason, GetClientIP(client, ip, sizeof(ip)); - static char query[255]; + char query[255]; + static char expiresDate[64]; if(time > 0) { Format(expiresDate, sizeof(expiresDate), "%d", GetTime() + (time * 60)); @@ -124,25 +146,36 @@ public Action OnBanClient(int client, int time, int flags, const char[] reason, } g_db.Format(query, sizeof(query), "INSERT INTO bans" - ..."(steamid, ip, reason, public_message, expires, executor, ip_banned)" - ..."VALUES ('%s', '%s', '%s', FROM_UNIXTIME(%s), '%s', 0)", + ..."(steamid, ip, reason, public_message, expires, executor, flags, timestamp)" + ..."VALUES ('%s', '%s', '%s', '%s', %s, '%s', %d, UNIX_TIMESTAMP())", identity, ip, reason, kick_message, expiresDate, - executor + executor, + BANFLAG_NONE ); - g_db.Query(DB_OnBanQuery, query, pack); + static char strKey[8]; + int key = ++iPendingCounter; + IntToString(key, strKey, sizeof(strKey)); + pendingInsertQueries.SetString(strKey, query); + + + g_db.Format(query, sizeof(query), "SELECT `flags` FROM `bans` WHERE `expired` = 0 AND `steamid` LIKE 'STEAM_%%:%%:%s' OR ip = '%s'", identity[10], identity); + g_db.Query(DB_OnBanPreCheck, query, key); + return Plugin_Continue; } + + public Action OnRemoveBan(const char[] identity, int flags, const char[] command, any source) { if(flags == BANFLAG_AUTHID) { static char query[128]; g_db.Format(query, sizeof(query), "DELETE FROM `bans` WHERE steamid = '%s'", identity); - g_db.Query(DB_OnRemoveBanQuery, query, flags); + g_db.Query(DB_GenericCallback, query, flags); } return Plugin_Continue; @@ -151,6 +184,26 @@ public Action OnRemoveBan(const char[] identity, int flags, const char[] command /////////////////////////////////////////////////////////////////////////////// // DB Callbacks /////////////////////////////////////////////////////////////////////////////// +//] DB_OnBanQuery returned error: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '' at line 1 +public void DB_OnBanPreCheck(Database db, DBResultSet results, const char[] error, int key) { + static char strKey[8]; + IntToString(key, strKey, sizeof(strKey)); + static char query[255]; + pendingInsertQueries.GetString(strKey, query, sizeof(query)); + + if(results == null || db == INVALID_HANDLE) { + LogError("Ban Pre-check: Cannot check for existing ban, ignoring ban attempt. [Query: %s]", query); + } else { + if(results.FetchRow()) { + int flags = results.FetchInt(0); + if(~flags & BANFLAG_SUSPENDED) + LogMessage("Ban Pre-check: Found existing ban, ignoring ban attempt. [Query: %s]", query); + } else { + g_db.Query(DB_OnBanQuery, query); + } + } +} + public void DB_OnConnectCheck(Database db, DBResultSet results, const char[] error, int user) { int client = GetClientOfUserId(user); @@ -162,35 +215,49 @@ public void DB_OnConnectCheck(Database db, DBResultSet results, const char[] err } } else { //No failure, check the data. - if(client > 0 && results.FetchRow()) { //Is there a ban found? - static char reason[128], steamid[64]; - DBResult reasonResult; + while(client > 0 && results.FetchRow()) { //Is there a ban found? + static char reason[128], steamid[64], public_message[255]; + DBResult colResult; + results.FetchString(1, steamid, sizeof(steamid)); + results.FetchString(0, reason, sizeof(reason), colResult); + if(colResult == DBVal_Null) { + reason[0] = '\0'; + } + bool expired = results.FetchInt(2) == 1; //Check if computed column 'expired' is true if(results.IsFieldNull(2)) { //If expired null, delete i guess. lol DeleteBan(steamid); } else { - results.FetchString(0, reason, sizeof(reason), reasonResult); - if(!expired) { - LogAction(-1, client, "%N is banned from server: \"%s\"", client, reason); + int flags = results.FetchInt(4); + if(!expired && (~flags & BANFLAG_SUSPENDED)) { + LogAction(-1, client, "\"%L\" is banned from server: \"%s\"", client, reason); + // Fetch public message + results.FetchString(3, public_message, sizeof(public_message), colResult); + if(colResult == DBVal_Null || strlen(public_message) == 0) { + public_message = reason; + } + + int id = results.FetchInt(4); + if(hKickType.IntValue > 0) { - if(reasonResult == DBVal_Data) - KickClient(client, "You have been banned:\n%s", reason); + if(public_message[0] != '\0') + KickClient(client, "You have been banned:\n%s\n\nAppeal at jackz.me/apl/%d", public_message, id); else - KickClient(client, "You have been banned from this server."); + KickClient(client, "You have been banned from this server.\n\nAppeal at jackz.me/apl/%d", id); static char query[128]; g_db.Format(query, sizeof(query), "UPDATE bans SET times_tried=times_tried+1 WHERE steamid = '%s'", steamid); - g_db.Query(DB_OnBanQuery, query); + g_db.Query(DB_GenericCallback, query); } else { - PrintChatToAdmins("%N was banned from this server for: \"%s\"", client, reason); + PrintChatToAdmins("\"%L\" was banned from this server for: \"%s\"", client, reason); } static char query[128]; g_db.Format(query, sizeof(query), "UPDATE bans SET times_tried=times_tried+1 WHERE steamid = '%s'", steamid); - g_db.Query(DB_OnBanQuery, query); + g_db.Query(DB_GenericCallback, query); } else { LogAction(-1, client, "%N was previously banned from server: \"%s\"", client, reason); // User was previously banned - PrintChatToAdmins("%N has a previously expired ban of reason \"%s\"", client, reason); + PrintChatToAdmins("%N has a previous suspended/expired ban of reason \"%s\"", client, reason); } } } @@ -200,7 +267,7 @@ public void DB_OnConnectCheck(Database db, DBResultSet results, const char[] err void DeleteBan(const char[] steamid) { static char query[128]; g_db.Format(query, sizeof(query), "DELETE FROM `bans` WHERE steamid = '%s'", steamid); - g_db.Query(DB_OnRemoveBanQuery, query); + g_db.Query(DB_GenericCallback, query); } @@ -223,7 +290,7 @@ public void DB_OnBanQuery(Database db, DBResultSet results, const char[] error, } } -public void DB_OnRemoveBanQuery(Database db, DBResultSet results, const char[] error, any data) { +public void DB_GenericCallback(Database db, DBResultSet results, const char[] error, any data) { if(db == INVALID_HANDLE || results == null) { LogError("DB_OnRemoveBanQuery returned error: %s", error); }