- completely overhauled the immunity system

- updated and reorganized database schema files
- changed config files to show new immunity rules
- updated sql-admin-manager so it can update+create tables
- added compile.sh file for building plugins in batch
- deprecated the old admin-cache immunity api relying on ImmunityType
- added a new sm_config table to the schema for storing version numbers

--HG--
extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%401409
This commit is contained in:
David Anderson
2007-09-10 23:38:58 +00:00
parent 93581bb296
commit 6aec628ab0
23 changed files with 815 additions and 233 deletions
+22 -24
View File
@@ -110,22 +110,7 @@ public SMCResult:ReadGroups_KeyValue(Handle:smc,
SetAdmGroupAddFlag(g_CurGrp, flag, true);
}
} else if (StrEqual(key, "immunity")) {
/* If it's a value we know about, use it */
if (StrEqual(value, "*"))
{
SetAdmGroupImmunity(g_CurGrp, Immunity_Global, true);
} else if (StrEqual(value, "$")) {
SetAdmGroupImmunity(g_CurGrp, Immunity_Default, true);
} else {
/* If we can't find the group, we'll need to schedule a reparse */
new GroupId:id = FindAdmGroup(value);
if (id != INVALID_GROUP_ID)
{
SetAdmGroupImmuneFrom(g_CurGrp, id);
} else {
g_NeedReparse = true;
}
}
g_NeedReparse = true;
}
} else if (g_GroupState == GROUP_STATE_OVERRIDES) {
new OverrideRule:rule = Command_Deny;
@@ -147,18 +132,31 @@ public SMCResult:ReadGroups_KeyValue(Handle:smc,
/* Check for immunity again, core should handle double inserts */
if (StrEqual(key, "immunity"))
{
if (StrEqual(value, "$"))
/* If it's a value we know about, use it */
if (StrEqual(value, "*"))
{
SetAdmGroupImmunity(g_CurGrp, Immunity_Default, true);
} else if (StrEqual(value, "*")) {
SetAdmGroupImmunity(g_CurGrp, Immunity_Global, true);
SetAdmGroupImmunityLevel(g_CurGrp, 2);
} else if (StrEqual(value, "$")) {
SetAdmGroupImmunityLevel(g_CurGrp, 1);
} else {
new GroupId:id = FindAdmGroup(value);
if (id != INVALID_GROUP_ID)
new level;
if (StringToIntEx(value, level))
{
SetAdmGroupImmuneFrom(g_CurGrp, id);
SetAdmGroupImmunityLevel(g_CurGrp, level);
} else {
ParseError("Unable to find group: \"%s\"", value);
new GroupId:id;
if (value[0] == '@')
{
id = FindAdmGroup(value[1]);
} else {
id = FindAdmGroup(value);
}
if (id != INVALID_GROUP_ID)
{
SetAdmGroupImmuneFrom(g_CurGrp, id);
} else {
ParseError("Unable to find group: \"%s\"", value);
}
}
}
}
+22 -9
View File
@@ -111,30 +111,42 @@ ReadAdminLine(const String:line[])
new String:flags[64];
cur_idx = BreakString(line[idx], flags, sizeof(flags));
idx += cur_idx;
if (flags[0] == '@')
/* Read immunity level, if any */
new level, flag_idx;
if ((flag_idx = StringToIntEx(flags, level)) > 0)
{
new GroupId:gid = FindAdmGroup(flags[1]);
SetAdminImmunityLevel(admin, level);
if (flags[flag_idx] == ':')
{
flag_idx++;
}
}
if (flags[flag_idx] == '@')
{
new GroupId:gid = FindAdmGroup(flags[flag_idx + 1]);
if (gid == INVALID_GROUP_ID)
{
ParseError("Invalid group detected: %s", flags[1]);
ParseError("Invalid group detected: %s", flags[flag_idx + 1]);
return;
}
AdminInheritGroup(admin, gid);
} else {
new len = strlen(flags);
new len = strlen(flags[flag_idx]);
new bool:is_default = false;
for (new i=0; i<len; i++)
{
if (flags[i] == '$')
if (!level && flags[flag_idx + i] == '$')
{
is_default = true;
SetAdminImmunityLevel(admin, 1);
} else {
new AdminFlag:flag;
if (!FindFlagByChar(flags[i], flag))
if (!FindFlagByChar(flags[flag_idx + i], flag))
{
ParseError("Invalid flag detected: %c", flags[i]);
ParseError("Invalid flag detected: %c", flags[flag_idx + i]);
continue;
}
SetAdminFlag(admin, flag, true);
@@ -172,3 +184,4 @@ ReadAdminLine(const String:line[])
}
}
}
+17 -4
View File
@@ -89,12 +89,18 @@ public SMCResult:ReadUsers_KeyValue(Handle:smc,
{
auth = true;
strcopy(g_CurAuth, sizeof(g_CurAuth), value);
} else if (StrEqual(key, "identity")) {
}
else if (StrEqual(key, "identity"))
{
auth = true;
strcopy(g_CurIdent, sizeof(g_CurIdent), value);
} else if (StrEqual(key, "password")) {
}
else if (StrEqual(key, "password"))
{
SetAdminPassword(g_CurUser, value);
} else if (StrEqual(key, "group")) {
}
else if (StrEqual(key, "group"))
{
new GroupId:id = FindAdmGroup(value);
if (id == INVALID_GROUP_ID)
{
@@ -102,7 +108,9 @@ public SMCResult:ReadUsers_KeyValue(Handle:smc,
} else if (!AdminInheritGroup(g_CurUser, id)) {
ParseError("Unable to inherit group \"%s\"", value);
}
} else if (StrEqual(key, "flags")) {
}
else if (StrEqual(key, "flags"))
{
new len = strlen(value);
new AdminFlag:flag;
@@ -114,6 +122,11 @@ public SMCResult:ReadUsers_KeyValue(Handle:smc,
}
SetAdminFlag(g_CurUser, flag, true);
}
}
else if (StrEqual(key, "immunity"))
{
new level = StringToInt(value);
SetAdminImmunityLevel(g_CurUser, level);
}
if (auth && g_CurIdent[0] && g_CurAuth[0])
+14 -17
View File
@@ -112,7 +112,7 @@ FetchUsers(Handle:db)
decl String:query[255], String:error[255];
new Handle:hQuery, Handle:hGroupQuery;
Format(query, sizeof(query), "SELECT id, authtype, identity, password, flags, name FROM sm_admins");
Format(query, sizeof(query), "SELECT id, authtype, identity, password, flags, name, immunity FROM sm_admins");
if ((hQuery = SQL_Query(db, query)) == INVALID_HANDLE)
{
SQL_GetError(db, error, sizeof(error));
@@ -136,6 +136,7 @@ FetchUsers(Handle:db)
decl String:password[80];
decl String:flags[32];
decl String:name[80];
new immunity;
new AdminId:adm, id;
while (SQL_FetchRow(hQuery))
@@ -146,6 +147,7 @@ FetchUsers(Handle:db)
SQL_FetchString(hQuery, 3, password, sizeof(password));
SQL_FetchString(hQuery, 4, flags, sizeof(flags));
SQL_FetchString(hQuery, 5, name, sizeof(name));
immunity = SQL_FetchInt(hQuery, 6);
/* Use a pre-existing admin if we can */
if ((adm = FindAdminByIdentity(authtype, identity)) == INVALID_ADMIN_ID)
@@ -159,7 +161,7 @@ FetchUsers(Handle:db)
}
#if defined _DEBUG
PrintToServer("Found SQL admin (%d,%s,%s,%s,%s,%s):%d", id, authtype, identity, password, flags, name, adm);
PrintToServer("Found SQL admin (%d,%s,%s,%s,%s,%s,%d):%d", id, authtype, identity, password, flags, name, immunity, adm);
#endif
/* See if this admin wants a password */
@@ -179,6 +181,8 @@ FetchUsers(Handle:db)
}
SetAdminFlag(adm, flag, true);
}
SetAdminImmunityLevel(adm, immunity);
/* Look up groups */
if (hGroupQuery != INVALID_HANDLE)
@@ -196,7 +200,7 @@ FetchGroups(Handle:db)
decl String:query[255];
new Handle:hQuery;
Format(query, sizeof(query), "SELECT immunity, flags, name FROM sm_groups");
Format(query, sizeof(query), "SELECT flags, name, immunity_level FROM sm_groups");
if ((hQuery = SQL_Query(db, query)) == INVALID_HANDLE)
{
@@ -208,17 +212,17 @@ FetchGroups(Handle:db)
}
/* Now start fetching groups */
decl String:immunity[16];
decl String:flags[32];
decl String:name[128];
new immunity;
while (SQL_FetchRow(hQuery))
{
SQL_FetchString(hQuery, 0, immunity, sizeof(immunity));
SQL_FetchString(hQuery, 1, flags, sizeof(flags));
SQL_FetchString(hQuery, 2, name, sizeof(name));
SQL_FetchString(hQuery, 0, flags, sizeof(flags));
SQL_FetchString(hQuery, 1, name, sizeof(name));
immunity = SQL_FetchInt(hQuery, 2);
#if defined _DEBUG
PrintToServer("Adding group (%s, %s, %s)", immunity, flags, name);
PrintToServer("Adding group (%d, %s, %s)", immunity, flags, name);
#endif
/* Find or create the group */
@@ -241,15 +245,7 @@ FetchGroups(Handle:db)
}
/* Set the immunity level this group has */
if (StrEqual(immunity, "all"))
{
SetAdmGroupImmunity(gid, Immunity_Default, true);
SetAdmGroupImmunity(gid, Immunity_Global, true);
} else if (StrEqual(immunity, "default")) {
SetAdmGroupImmunity(gid, Immunity_Default, true);
} else if (StrEqual(immunity, "global")) {
SetAdmGroupImmunity(gid, Immunity_Global, true);
}
SetAdmGroupImmunityLevel(gid, immunity);
}
CloseHandle(hQuery);
@@ -387,3 +383,4 @@ FetchOverrides(Handle:db)
CloseHandle(hQuery);
}
+14 -84
View File
@@ -352,6 +352,7 @@ public OnReceiveUser(Handle:owner, Handle:hndl, const String:error[], any:data)
decl String:flags[32];
decl String:name[80];
new AdminId:adm, id;
new immunity;
/**
* Cache user info -- [0] = db id, [1] = cache id, [2] = groups
@@ -367,6 +368,7 @@ public OnReceiveUser(Handle:owner, Handle:hndl, const String:error[], any:data)
SQL_FetchString(hndl, 3, password, sizeof(password));
SQL_FetchString(hndl, 4, flags, sizeof(flags));
SQL_FetchString(hndl, 5, name, sizeof(name));
immunity = SQL_FetchInt(hndl, 7);
/* For dynamic admins we clear anything already in the cache. */
if ((adm = FindAdminByIdentity(authtype, identity)) != INVALID_ADMIN_ID)
@@ -387,7 +389,7 @@ public OnReceiveUser(Handle:owner, Handle:hndl, const String:error[], any:data)
total_users++;
#if defined _DEBUG
PrintToServer("Found SQL admin (%d,%s,%s,%s,%s,%s):%d:%d", id, authtype, identity, password, flags, name, adm, user_lookup[total_users-1][2]);
PrintToServer("Found SQL admin (%d,%s,%s,%s,%s,%s,%d):%d:%d", id, authtype, identity, password, flags, name, immunity, adm, user_lookup[total_users-1][2]);
#endif
/* See if this admin wants a password */
@@ -395,6 +397,8 @@ public OnReceiveUser(Handle:owner, Handle:hndl, const String:error[], any:data)
{
SetAdminPassword(adm, password);
}
SetAdminImmunityLevel(adm, immunity);
/* Apply each flag */
new len = strlen(flags);
@@ -488,7 +492,7 @@ FetchUser(Handle:db, client)
decl String:query[512];
new len = 0;
len += Format(query[len], sizeof(query)-len, "SELECT a.id, a.authtype, a.identity, a.password, a.flags, a.name, COUNT(ag.group_id)");
len += Format(query[len], sizeof(query)-len, "SELECT a.id, a.authtype, a.identity, a.password, a.flags, a.name, COUNT(ag.group_id), immunity");
len += Format(query[len], sizeof(query)-len, " FROM sm_admins a LEFT JOIN sm_admins_groups ag ON a.id = ag.admin_id WHERE ");
len += Format(query[len], sizeof(query)-len, " (a.authtype = 'ip' AND a.identity = '%s')", ipaddr);
len += Format(query[len], sizeof(query)-len, " OR (a.authtype = 'name' AND a.identity = '%s')", safe_name);
@@ -710,17 +714,17 @@ public OnReceiveGroups(Handle:owner, Handle:hndl, const String:error[], any:data
/**
* Now start fetching groups.
*/
decl String:immunity[16];
decl String:flags[32];
decl String:name[128];
new immunity;
while (SQL_FetchRow(hndl))
{
SQL_FetchString(hndl, 0, immunity, sizeof(immunity));
SQL_FetchString(hndl, 1, flags, sizeof(flags));
SQL_FetchString(hndl, 2, name, sizeof(name));
SQL_FetchString(hndl, 0, flags, sizeof(flags));
SQL_FetchString(hndl, 1, name, sizeof(name));
immunity = SQL_FetchInt(hndl, 2);
#if defined _DEBUG
PrintToServer("Adding group (%s, %s, %s)", immunity, flags, name);
PrintToServer("Adding group (%d, %s, %s)", immunity, flags, name);
#endif
/* Find or create the group */
@@ -729,7 +733,7 @@ public OnReceiveGroups(Handle:owner, Handle:hndl, const String:error[], any:data
{
gid = CreateAdmGroup(name);
}
/* Add flags from the database to the group */
new num_flag_chars = strlen(flags);
for (new i=0; i<num_flag_chars; i++)
@@ -742,16 +746,7 @@ public OnReceiveGroups(Handle:owner, Handle:hndl, const String:error[], any:data
SetAdmGroupAddFlag(gid, flag, true);
}
/* Set the immunity level this group has */
if (StrEqual(immunity, "all"))
{
SetAdmGroupImmunity(gid, Immunity_Default, true);
SetAdmGroupImmunity(gid, Immunity_Global, true);
} else if (StrEqual(immunity, "default")) {
SetAdmGroupImmunity(gid, Immunity_Default, true);
} else if (StrEqual(immunity, "global")) {
SetAdmGroupImmunity(gid, Immunity_Global, true);
}
SetAdmGroupImmunityLevel(gid, immunity);
}
/**
@@ -774,7 +769,7 @@ FetchGroups(Handle:db, sequence)
decl String:query[255];
new Handle:pk;
Format(query, sizeof(query), "SELECT immunity, flags, name FROM sm_groups");
Format(query, sizeof(query), "SELECT flags, name, immunity_level FROM sm_groups");
pk = CreateDataPack();
WritePackCell(pk, sequence);
@@ -858,68 +853,3 @@ FetchOverrides(Handle:db, sequence)
SQL_TQuery(db, OnReceiveOverrides, query, pk, DBPrio_High);
}
/**
* Finds an entry in a temporary group list (used by immunity resolver).
*
* @param group_list Array(3,n) (0=db id, 1=gid, 2=immunity list)
* @param id group database id
* @return GroupId of the database id or INVALID_GROUP_ID.
*/
stock GroupId:UTIL_FindGroupInCache(Handle:group_list, id)
{
new size = GetArraySize(group_list);
for (new i=0; i<size; i++)
{
decl data[3];
GetArrayArray(group_list, i, data);
if (data[0] == id)
{
return GroupId:data[1];
}
}
return INVALID_GROUP_ID;
}
/**
* Breaks a comma-delimited string into a list of numbers, returning a new
* dynamic array.
*
* @param text The string to split.
* @return A new array Handle which must be closed, or
* INVALID_HANDLE on no strings found.
*/
stock Handle:UTIL_ExplodeNumberString(const String:text[])
{
new Handle:array = INVALID_HANDLE;
decl String:buffer[32];
new reloc_idx, idx;
while ((idx = SplitString(text[reloc_idx], ",", buffer, sizeof(buffer))) != -1)
{
reloc_idx += idx;
if (text[reloc_idx] == '\0')
{
break;
}
if (array == INVALID_HANDLE)
{
array = CreateArray();
}
PushArrayCell(array, StringToInt(buffer));
}
if (text[reloc_idx] != '\0')
{
if (array == INVALID_HANDLE)
{
array = CreateArray();
}
PushArrayCell(array, StringToInt(text[reloc_idx]));
}
return array;
}
+11
View File
@@ -0,0 +1,11 @@
#!/bin/bash
test -e compiled || mkdir compiled
for sourcefile in *.sp
do
smxfile="`echo $sourcefile | sed -e 's/\.sp$/\.smx/'`"
echo -n "Compiling $sourcefile ..."
./spcomp $sourcefile -ocompiled/$smxfile
done
+53 -14
View File
@@ -125,12 +125,12 @@ enum OverrideRule
};
/**
* Immunity types.
* DEPRECATED, do not use.
*/
enum ImmunityType
{
Immunity_Default = 1, /**< Immune from everyone with no immunity */
Immunity_Global, /**< Immune from everyone (except root admins) */
Immunity_Default = 1, /**< Deprecated. */
Immunity_Global, /**< Deprecated. */
};
/**
@@ -261,22 +261,15 @@ native bool:GetAdmGroupAddFlag(GroupId:id, AdminFlag:flag);
native GetAdmGroupAddFlags(GroupId:id);
/**
* Toggles a generic immunity type.
*
* @param id Group id.
* @param type Generic immunity type.
* @param enabled True to enable, false otherwise.
* @noreturn
* @deprecated Functionality removed.
*/
#pragma deprecated Use SetAdmGroupImmunityLevel() instead.
native SetAdmGroupImmunity(GroupId:id, ImmunityType:type, bool:enabled);
/**
* Returns whether or not a group has global immunity.
*
* @param id Group id.
* @param type Generic immunity type.
* @return True if the group has this immunity, false otherwise.
* @deprecated Functionality removed.
*/
#pragma deprecated Use GetAdmGroupImmunityLevel() instead.
native bool:GetAdmGroupImmunity(GroupId:id, ImmunityType:type);
/**
@@ -535,6 +528,18 @@ native ReadFlagString(const String:flags[], &numchars=0);
/**
* Tests whether one admin can target another.
*
* The hueristics for this check are as follows:
* 0. If the targeting AdminId is INVALID_ADMIN_ID, targeting fails.
* 1. If the targeted AdminId is INVALID_ADMIN_ID, targeting succeeds.
* 2. If the targeted AdminId is the same as the targeting AdminId,
* (self) targeting succeeds.
* 3. If the targeting admin is root, targeting succeeds.
* 4. If the targeted admin has access higher (as interpreted by
* (sm_immunity_mode) than the targeting admin, then targeting fails.
* 5. If the targeted admin has specific immunity from the
* targeting admin via group immunities, targeting fails.
* 6. Targeting succeeds.
*
* @param admin Admin doing the targetting (may be INVALID_ADMIN_ID).
* @param target Target admin (may be INVALID_ADMIN_ID).
* @return True if targetable, false if immune.
@@ -550,6 +555,40 @@ native CanAdminTarget(AdminId:admin, AdminId:target);
*/
native bool:CreateAuthMethod(const String:method[]);
/**
* Sets a group's immunity level.
*
* @param gid Group Id.
* @param level Immunity level value.
* @return Old immunity level value.
*/
native SetAdmGroupImmunityLevel(GroupId:gid, level);
/**
* Gets a group's immunity level (defaults to 0).
*
* @param gid Group Id.
* @return Immunity level value.
*/
native GetAdmGroupImmunityLevel(GroupId:gid);
/**
* Sets an admin's immunity level.
*
* @param id Admin Id.
* @param level Immunity level value.
* @return Old immunity level value.
*/
native SetAdminImmunityLevel(AdminId:id, level);
/**
* Gets an admin's immunity level.
*
* @param id Admin Id.
* @return Immunity level value.
*/
native GetAdminImmunityLevel(AdminId:id);
/**
* Converts a flag to its single bit.
*
+348 -13
View File
@@ -36,6 +36,11 @@
#include <sourcemod>
#define CURRENT_SCHEMA_VERSION 1409
#define SCHEMA_UPGRADE_1 1409
new current_version[4] = {1, 0, 0, CURRENT_SCHEMA_VERSION};
public Plugin:myinfo =
{
name = "SQL Admin Manager",
@@ -55,6 +60,8 @@ public OnPluginStart()
RegAdminCmd("sm_sql_addgroup", Command_AddGroup, ADMFLAG_ROOT, "Adds a group to the SQL database");
RegAdminCmd("sm_sql_delgroup", Command_DelGroup, ADMFLAG_ROOT, "Removes a group from the SQL database");
RegAdminCmd("sm_sql_setadmingroups", Command_SetAdminGroups, ADMFLAG_ROOT, "Sets an admin's groups in the SQL database");
RegServerCmd("sm_create_adm_tables", Command_CreateTables);
RegServerCmd("sm_update_adm_tables", Command_UpdateTables);
}
Handle:Connect()
@@ -77,6 +84,310 @@ Handle:Connect()
return db;
}
CreateMySQL(client, Handle:db)
{
new String:queries[7][] =
{
"CREATE TABLE sm_admins (id int(10) unsigned NOT NULL auto_increment, authtype enum('steam','name','ip') NOT NULL, identity varchar(65) NOT NULL, password varchar(65), flags varchar(30) NOT NULL, name varchar(65) NOT NULL, immunity int(10) unsigned NOT NULL, PRIMARY KEY (id))",
"CREATE TABLE sm_groups (id int(10) unsigned NOT NULL auto_increment, flags varchar(30) NOT NULL, name varchar(120) NOT NULL, immunity_level int(1) unsigned NOT NULL, PRIMARY KEY (id))",
"CREATE TABLE sm_group_immunity (group_id int(10) unsigned NOT NULL, other_id int(10) unsigned NOT NULL, PRIMARY KEY (group_id, other_id))",
"CREATE TABLE sm_group_overrides (group_id int(10) unsigned NOT NULL, type enum('command','group') NOT NULL, name varchar(32) NOT NULL, access enum('allow','deny') NOT NULL, PRIMARY KEY (group_id, type, name))",
"CREATE TABLE sm_overrides (type enum('command','group') NOT NULL, name varchar(32) NOT NULL, flags varchar(30) NOT NULL, PRIMARY KEY (type,name))",
"CREATE TABLE sm_admins_groups (admin_id int(10) unsigned NOT NULL, group_id int(10) unsigned NOT NULL, inherit_order int(10) NOT NULL, PRIMARY KEY (admin_id, group_id))",
"CREATE TABLE IF NOT EXISTS sm_config (cfg_key varchar(32) NOT NULL, cfg_value varchar(255) NOT NULL, PRIMARY KEY (cfg_key))"
};
for (new i = 0; i < 7; i++)
{
if (!DoQuery(client, db, queries[i]))
{
return;
}
}
decl String:query[256];
Format(query,
sizeof(query),
"INSERT INTO sm_config (cfg_key, cfg_value) VALUES ('admin_version', '1.0.0.%d') ON DUPLICATE KEY UPDATE cfg_value = '1.0.0.%d'",
CURRENT_SCHEMA_VERSION,
CURRENT_SCHEMA_VERSION);
if (!DoQuery(client, db, query))
{
return;
}
ReplyToCommand(client, "[SM] Admin tables have been created.");
}
CreateSQLite(client, Handle:db)
{
new String:queries[7][] =
{
"CREATE TABLE sm_admins (id INTEGER PRIMARY KEY AUTOINCREMENT, authtype varchar(16) NOT NULL CHECK(authtype IN ('steam', 'ip', 'name')), identity varchar(65) NOT NULL, password varchar(65), flags varchar(30) NOT NULL, name varchar(65) NOT NULL, immunity INTEGER NOT NULL)",
"CREATE TABLE sm_groups (id INTEGER PRIMARY KEY AUTOINCREMENT, flags varchar(30) NOT NULL, name varchar(120) NOT NULL, immunity_level INTEGER NOT NULL)",
"CREATE TABLE sm_group_immunity (group_id INTEGER NOT NULL, other_id INTEGER NOT NULL, PRIMARY KEY (group_id, other_id))",
"CREATE TABLE sm_group_overrides (group_id INTEGER NOT NULL, type varchar(16) NOT NULL CHECK (type IN ('command', 'group')), name varchar(32) NOT NULL, access varchar(16) NOT NULL CHECK (access IN ('allow', 'deny')), PRIMARY KEY (group_id, type, name))",
"CREATE TABLE sm_overrides (type varchar(16) NOT NULL CHECK (type IN ('command', 'group')), name varchar(32) NOT NULL, flags varchar(30) NOT NULL, PRIMARY KEY (type,name))",
"CREATE TABLE sm_admins_groups (admin_id INTEGER NOT NULL, group_id INTEGER NOT NULL, inherit_order int(10) NOT NULL, PRIMARY KEY (admin_id, group_id))",
"CREATE TABLE IF NOT EXISTS sm_config (cfg_key varchar(32) NOT NULL, cfg_value varchar(255) NOT NULL, PRIMARY KEY (cfg_key))"
};
for (new i = 0; i < 7; i++)
{
if (!DoQuery(client, db, queries[i]))
{
return;
}
}
decl String:query[256];
Format(query,
sizeof(query),
"REPLACE INTO sm_config (cfg_key, cfg_value) VALUES ('admin_version', '1.0.0.%d')",
CURRENT_SCHEMA_VERSION);
if (!DoQuery(client, db, query))
{
return;
}
ReplyToCommand(client, "[SM] Admin tables have been created.");
}
public Action:Command_CreateTables(args)
{
new client = 0;
new Handle:db = Connect();
if (db == INVALID_HANDLE)
{
ReplyToCommand(client, "[SM] %t", "Could not connect to database");
return Plugin_Handled;
}
new String:ident[16];
SQL_ReadDriver(db, ident, sizeof(ident));
if (strcmp(ident, "mysql") == 0)
{
CreateMySQL(client, db);
} else if (strcmp(ident, "sqlite") == 0) {
CreateSQLite(client, db);
} else {
ReplyToCommand(client, "[SM] Unknown driver type '%s', cannot create tables.", ident);
}
CloseHandle(db);
return Plugin_Handled;
}
bool:GetUpdateVersion(client, Handle:db, versions[4])
{
decl String:query[256];
new Handle:hQuery;
Format(query, sizeof(query), "SELECT cfg_value FROM sm_config WHERE cfg_key = 'admin_version'");
if ((hQuery = SQL_Query(db, query)) == INVALID_HANDLE)
{
DoError(client, db, query, "Version lookup query failed");
return false;
}
if (SQL_FetchRow(hQuery))
{
decl String:version_string[255];
SQL_FetchString(hQuery, 0, version_string, sizeof(version_string));
decl String:version_numbers[4][12];
if (ExplodeString(version_string, ".", version_numbers, 4, 12) == 4)
{
for (new i = 0; i < 4; i++)
{
versions[i] = StringToInt(version_numbers[i]);
}
}
}
CloseHandle(hQuery);
if (current_version[3] < versions[3])
{
ReplyToCommand(client, "[SM] The database is newer than the expected version.");
return false;
}
if (current_version[3] == versions[3])
{
ReplyToCommand(client, "[SM] Your tables are already up to date.");
return false;
}
return true;
}
UpdateSQLite(client, Handle:db)
{
decl String:query[512];
new Handle:hQuery;
Format(query, sizeof(query), "SELECT name FROM sqlite_master WHERE type = 'table' AND name = 'sm_config'");
if ((hQuery = SQL_Query(db, query)) == INVALID_HANDLE)
{
DoError(client, db, query, "Table lookup query failed");
return;
}
new bool:found = SQL_FetchRow(hQuery);
CloseHandle(hQuery);
new versions[4];
if (found)
{
if (!GetUpdateVersion(client, db, versions))
{
return;
}
}
/* We only know about one upgrade path right now...
* 0 => 1
*/
if (versions[3] < SCHEMA_UPGRADE_1)
{
new String:queries[8][] =
{
"ALTER TABLE sm_admins ADD immunity INTEGER DEFAULT 0 NOT NULL",
"CREATE TABLE _sm_groups_temp (id INTEGER PRIMARY KEY AUTOINCREMENT, flags varchar(30) NOT NULL, name varchar(120) NOT NULL, immunity_level INTEGER DEFAULT 0 NOT NULL)",
"INSERT INTO _sm_groups_temp (id, flags, name) SELECT id, flags, name FROM sm_groups",
"UPDATE _sm_groups_temp SET immunity_level = 2 WHERE id IN (SELECT g.id FROM sm_groups g WHERE g.immunity = 'global')",
"UPDATE _sm_groups_temp SET immunity_level = 1 WHERE id IN (SELECT g.id FROM sm_groups g WHERE g.immunity = 'default')",
"DROP TABLE sm_groups",
"ALTER TABLE _sm_groups_temp RENAME TO sm_groups",
"CREATE TABLE IF NOT EXISTS sm_config (cfg_key varchar(32) NOT NULL, cfg_value varchar(255) NOT NULL, PRIMARY KEY (cfg_key))"
};
for (new i = 0; i < 8; i++)
{
if (!DoQuery(client, db, queries[i]))
{
return;
}
}
Format(query,
sizeof(query),
"REPLACE INTO sm_config (cfg_key, cfg_value) VALUES ('admin_version', '1.0.0.%d')",
SCHEMA_UPGRADE_1);
if (!DoQuery(client, db, query))
{
return;
}
versions[3] = SCHEMA_UPGRADE_1;
}
ReplyToCommand(client, "[SM] Your tables are now up to date.");
}
UpdateMySQL(client, Handle:db)
{
decl String:query[512];
new Handle:hQuery;
Format(query, sizeof(query), "SHOW TABLES");
if ((hQuery = SQL_Query(db, query)) == INVALID_HANDLE)
{
DoError(client, db, query, "Table lookup query failed");
return;
}
decl String:table[64];
new bool:found = false;
while (SQL_FetchRow(hQuery))
{
SQL_FetchString(hQuery, 0, table, sizeof(table));
if (strcmp(table, "sm_config") == 0)
{
found = true;
}
}
CloseHandle(hQuery);
new versions[4];
if (found && !GetUpdateVersion(client, db, versions))
{
return;
}
/* We only know about one upgrade path right now...
* 0 => 1
*/
if (versions[3] < SCHEMA_UPGRADE_1)
{
new String:queries[6][] =
{
"CREATE TABLE IF NOT EXISTS sm_config (cfg_key varchar(32) NOT NULL, cfg_value varchar(255) NOT NULL, PRIMARY KEY (cfg_key))",
"ALTER TABLE sm_admins ADD immunity INT UNSIGNED NOT NULL",
"ALTER TABLE sm_groups ADD immunity_level INT UNSIGNED NOT NULL",
"UPDATE sm_groups SET immunity_level = 2 WHERE immunity = 'default'",
"UPDATE sm_groups SET immunity_level = 1 WHERE immunity = 'global'",
"ALTER TABLE sm_groups DROP immunity"
};
for (new i = 0; i < 6; i++)
{
if (!DoQuery(client, db, queries[i]))
{
return;
}
}
decl String:upgr[48];
Format(upgr, sizeof(upgr), "1.0.0.%d", SCHEMA_UPGRADE_1);
Format(query, sizeof(query), "INSERT INTO sm_config (cfg_key, cfg_value) VALUES ('admin_version', '%s') ON DUPLICATE KEY UPDATE cfg_value = '%s'", upgr, upgr);
if (!DoQuery(client, db, query))
{
return;
}
versions[3] = SCHEMA_UPGRADE_1;
}
ReplyToCommand(client, "[SM] Your tables are now up to date.");
}
public Action:Command_UpdateTables(args)
{
new client = 0;
new Handle:db = Connect();
if (db == INVALID_HANDLE)
{
ReplyToCommand(client, "[SM] %t", "Could not connect to database");
return Plugin_Handled;
}
new String:ident[16];
SQL_ReadDriver(db, ident, sizeof(ident));
if (strcmp(ident, "mysql") == 0)
{
UpdateMySQL(client, db);
} else if (strcmp(ident, "sqlite") == 0) {
UpdateSQLite(client, db);
} else {
ReplyToCommand(client, "[SM] Unknown driver type, cannot upgrade.");
}
CloseHandle(db);
return Plugin_Handled;
}
public Action:Command_SetAdminGroups(client, args)
{
if (args < 2)
@@ -296,17 +607,15 @@ public Action:Command_AddGroup(client, args)
if (args < 2)
{
ReplyToCommand(client, "[SM] Usage: sm_sql_addgroup <name> <flags> [immunity]");
ReplyToCommand(client, "[SM] %t", "Invalid immunity");
return Plugin_Handled;
}
new String:immunity[32] = "none";
new immunity;
if (args >= 3)
{
GetCmdArg(3, immunity, sizeof(immunity));
if (!StrEqual(immunity, "none")
&& !StrEqual(immunity, "global")
&& !StrEqual(immunity, "default"))
new String:arg3[32];
GetCmdArg(3, arg3, sizeof(arg3));
if (!StringToIntEx(arg3, immunity))
{
ReplyToCommand(client, "[SM] %t", "Invalid immunity");
return Plugin_Handled;
@@ -350,10 +659,9 @@ public Action:Command_AddGroup(client, args)
Format(query,
sizeof(query),
"INSERT INTO sm_groups (immunity, flags, name) VALUES ('%s', '%s', '%s')",
immunity,
"INSERT INTO sm_groups (flags, name, immunity_level) VALUES ('%s', '%s', '%d')",
safe_flags,
safe_name);
immunity);
if (!SQL_FastQuery(db, query))
{
@@ -448,7 +756,7 @@ public Action:Command_AddAdmin(client, args)
{
if (args < 4)
{
ReplyToCommand(client, "[SM] Usage: sm_sql_addadmin <alias> <authtype> <identity> <flags> [password]");
ReplyToCommand(client, "[SM] Usage: sm_sql_addadmin <alias> <authtype> <identity> <flags> [immunity] [password]");
ReplyToCommand(client, "[SM] %t", "Invalid authtype");
return Plugin_Handled;
}
@@ -463,6 +771,18 @@ public Action:Command_AddAdmin(client, args)
ReplyToCommand(client, "[SM] %t", "Invalid authtype");
return Plugin_Handled;
}
new immunity;
if (args >= 5)
{
new String:arg5[32];
GetCmdArg(5, arg5, sizeof(arg5));
if (!StringToIntEx(arg5, immunity))
{
ReplyToCommand(client, "[SM] %t", "Invalid immunity");
return Plugin_Handled;
}
}
decl String:identity[65];
decl String:safe_identity[140];
@@ -516,12 +836,12 @@ public Action:Command_AddAdmin(client, args)
}
new len = 0;
len += Format(query[len], sizeof(query)-len, "INSERT INTO sm_admins (authtype, identity, password, flags, name) VALUES");
len += Format(query[len], sizeof(query)-len, "INSERT INTO sm_admins (authtype, identity, password, flags, name, immunity) VALUES");
if (safe_password[0] == '\0')
{
len += Format(query[len], sizeof(query)-len, " ('%s', '%s', NULL, '%s', '%s')", authtype, safe_identity, safe_flags, safe_alias);
len += Format(query[len], sizeof(query)-len, " ('%s', '%s', NULL, '%s', '%s', %d)", authtype, safe_identity, safe_flags, safe_alias, immunity);
} else {
len += Format(query[len], sizeof(query)-len, " ('%s', '%s', '%s', '%s', '%s')", authtype, safe_identity, safe_password, safe_flags, safe_alias);
len += Format(query[len], sizeof(query)-len, " ('%s', '%s', '%s', '%s', '%s', %d)", authtype, safe_identity, safe_password, safe_flags, safe_alias, immunity);
}
if (!SQL_FastQuery(db, query))
@@ -536,6 +856,21 @@ public Action:Command_AddAdmin(client, args)
return Plugin_Handled;
}
stock bool:DoQuery(client, Handle:db, const String:query[])
{
if (!SQL_FastQuery(db, query))
{
decl String:error[255];
SQL_GetError(db, error, sizeof(error));
LogError("Query failed: %s", error);
LogError("Query dump: %s", query);
ReplyToCommand(client, "[SM] %t", "Failed to query database");
return false;
}
return true;
}
stock Action:DoError(client, Handle:db, const String:query[], const String:msg[])
{
decl String:error[255];