flag letter assignment is now handled by core
authorDavid Anderson <dvander@alliedmods.net>
Fri Aug 10 04:53:30 2007 +0000 (2007-08-10)
changeset 12989cddbed74581
parent 1297 423d171fafac
child 1299 10f58032bc78
flag letter assignment is now handled by core
core/AdminCache.cpp
core/AdminCache.h
core/smn_admin.cpp
plugins/admin-flatfile/admin-flatfile.sp
plugins/admin-flatfile/admin-groups.sp
plugins/admin-flatfile/admin-levels.sp
plugins/admin-flatfile/admin-overrides.sp
plugins/admin-flatfile/admin-simple.sp
plugins/admin-flatfile/admin-users.sp
plugins/include/admin.inc
public/IAdminSystem.h
     1.1 --- a/core/AdminCache.cpp	Fri Aug 10 01:07:07 2007 +0000
     1.2 +++ b/core/AdminCache.cpp	Fri Aug 10 04:53:30 2007 +0000
     1.3 @@ -37,8 +37,181 @@
     1.4  #include "ForwardSys.h"
     1.5  #include "PlayerManager.h"
     1.6  #include "ConCmdManager.h"
     1.7 +#include "TextParsers.h"
     1.8 +#include "Logger.h"
     1.9 +#include "sourcemod.h"
    1.10 +#include "sm_stringutil.h"
    1.11 +
    1.12 +#define LEVEL_STATE_NONE		0
    1.13 +#define LEVEL_STATE_LEVELS		1
    1.14 +#define LEVEL_STATE_FLAGS		2
    1.15  
    1.16  AdminCache g_Admins;
    1.17 +AdminFlag g_FlagLetters[26];
    1.18 +bool g_FlagSet[26];
    1.19 +
    1.20 +/* Default flags */
    1.21 +AdminFlag g_DefaultFlags[26] = 
    1.22 +{
    1.23 +	Admin_Reservation, Admin_Generic, Admin_Kick, Admin_Ban, Admin_Unban,
    1.24 +	Admin_Slay, Admin_Changemap, Admin_Convars, Admin_Config, Admin_Chat,
    1.25 +	Admin_Vote, Admin_Password, Admin_RCON, Admin_Cheats, Admin_Custom1, 
    1.26 +	Admin_Custom2, Admin_Custom3, Admin_Custom4, Admin_Custom5, Admin_Custom6,
    1.27 +	Admin_Generic, Admin_Generic, Admin_Generic, Admin_Generic, Admin_Generic,
    1.28 +	Admin_Root
    1.29 +};
    1.30 +
    1.31 +
    1.32 +class FlagReader : public ITextListener_SMC
    1.33 +{
    1.34 +public:
    1.35 +	void LoadLevels()
    1.36 +	{
    1.37 +		if (!Parse())
    1.38 +		{
    1.39 +			memcpy(g_FlagLetters, g_DefaultFlags, sizeof(AdminFlag) * 26);
    1.40 +			for (unsigned int i=0; i<20; i++)
    1.41 +			{
    1.42 +				g_FlagSet[i] = true;
    1.43 +			}
    1.44 +			g_FlagSet[25] = true;
    1.45 +		}
    1.46 +	}
    1.47 +private:
    1.48 +	bool Parse()
    1.49 +	{
    1.50 +		unsigned int line = 0;
    1.51 +		SMCParseError error;
    1.52 +
    1.53 +		m_Line = 0;
    1.54 +		m_bFileNameLogged = false;
    1.55 +		g_SourceMod.BuildPath(Path_SM, m_File, sizeof(m_File), "configs/admin_levels.cfg");
    1.56 +
    1.57 +		if ((error = g_TextParser.ParseFile_SMC(m_File, this, &line, NULL))
    1.58 +			!= SMCParse_Okay)
    1.59 +		{
    1.60 +			const char *err_string = g_TextParser.GetSMCErrorString(error);
    1.61 +			if (!err_string)
    1.62 +			{
    1.63 +				err_string = "Unknown error";
    1.64 +			}
    1.65 +			ParseError("Error %d (%s)", error, err_string);
    1.66 +			return false;
    1.67 +		}
    1.68 +
    1.69 +		return true;
    1.70 +	}
    1.71 +	void ReadSMC_ParseStart()
    1.72 +	{
    1.73 +		m_LevelState = LEVEL_STATE_NONE;
    1.74 +		m_IgnoreLevel = 0;
    1.75 +		memset(g_FlagSet, 0, sizeof(g_FlagSet));
    1.76 +	}
    1.77 +	SMCParseResult ReadSMC_NewSection(const char *name, bool opt_quotes)
    1.78 +	{
    1.79 +		if (m_IgnoreLevel)
    1.80 +		{
    1.81 +			m_IgnoreLevel++;
    1.82 +			return SMCParse_Continue;
    1.83 +		}
    1.84 +
    1.85 +		if (m_LevelState == LEVEL_STATE_NONE)
    1.86 +		{
    1.87 +			if (strcmp(name, "Levels") == 0)
    1.88 +			{
    1.89 +				m_IgnoreLevel = LEVEL_STATE_LEVELS;
    1.90 +			} else {
    1.91 +				m_IgnoreLevel++;
    1.92 +			}
    1.93 +		} else if (m_IgnoreLevel == LEVEL_STATE_LEVELS) {
    1.94 +			if (strcmp(name, "Flags") == 0)
    1.95 +			{
    1.96 +				m_IgnoreLevel = LEVEL_STATE_FLAGS;
    1.97 +			} else {
    1.98 +				m_IgnoreLevel++;
    1.99 +			}
   1.100 +		} else {
   1.101 +			m_IgnoreLevel++;
   1.102 +		}
   1.103 +
   1.104 +		return SMCParse_Continue;
   1.105 +	}
   1.106 +	SMCParseResult ReadSMC_KeyValue(const char *key, const char *value, bool key_quotes, bool value_quotes)
   1.107 +	{
   1.108 +		if (m_IgnoreLevel != LEVEL_STATE_FLAGS || m_IgnoreLevel)
   1.109 +		{
   1.110 +			return SMCParse_Continue;
   1.111 +		}
   1.112 +
   1.113 +		unsigned char c = (unsigned)value[0];
   1.114 +
   1.115 +		if (c < (unsigned)'a' || c > (unsigned)'z')
   1.116 +		{
   1.117 +			ParseError("Flag \"%c\" is not a lower-case ASCII letter", c);
   1.118 +			return SMCParse_Continue;
   1.119 +		}
   1.120 +
   1.121 +		c -= (unsigned)'a';
   1.122 +
   1.123 +		assert(c >= 0 && c < 26);
   1.124 +
   1.125 +		if (!g_Admins.FindFlag(key, &g_FlagLetters[c]))
   1.126 +		{
   1.127 +			ParseError("Unrecognized admin level \"%s\"", key);
   1.128 +			return SMCParse_Continue;
   1.129 +		}
   1.130 +
   1.131 +		g_FlagSet[c] = true;
   1.132 +
   1.133 +		return SMCParse_Continue;
   1.134 +	}
   1.135 +	SMCParseResult ReadSMC_LeavingSection()
   1.136 +	{
   1.137 +		if (m_IgnoreLevel)
   1.138 +		{
   1.139 +			m_IgnoreLevel--;
   1.140 +			return SMCParse_Continue;
   1.141 +		}
   1.142 +
   1.143 +		if (m_LevelState == LEVEL_STATE_FLAGS)
   1.144 +		{
   1.145 +			m_LevelState = LEVEL_STATE_LEVELS;
   1.146 +			return SMCParse_Halt;
   1.147 +		} else if (m_LevelState == LEVEL_STATE_LEVELS) {
   1.148 +			m_LevelState = LEVEL_STATE_NONE;
   1.149 +		}
   1.150 +
   1.151 +		return SMCParse_Continue;
   1.152 +	}
   1.153 +	SMCParseResult ReadSMC_RawLine(const char *line, unsigned int curline)
   1.154 +	{
   1.155 +		m_Line = curline;
   1.156 +		return SMCParse_Continue;
   1.157 +	}
   1.158 +	void ParseError(const char *message, ...)
   1.159 +	{
   1.160 +		va_list ap;
   1.161 +		char buffer[256];
   1.162 +
   1.163 +		va_start(ap, message);
   1.164 +		UTIL_FormatArgs(buffer, sizeof(buffer), message, ap);
   1.165 +		va_end(ap);
   1.166 +
   1.167 +		if (!m_bFileNameLogged)
   1.168 +		{
   1.169 +			g_Logger.LogError("[SM] Parse error(s) detected in file \"%s\":", m_File);
   1.170 +			m_bFileNameLogged = true;
   1.171 +		}
   1.172 +
   1.173 +		g_Logger.LogError("[SM] (Line %d): %s", m_Line, buffer);
   1.174 +	}
   1.175 +private:
   1.176 +	bool m_bFileNameLogged;
   1.177 +	char m_File[PLATFORM_MAX_PATH];
   1.178 +	int m_LevelState;
   1.179 +	int m_IgnoreLevel;
   1.180 +	unsigned int m_Line;
   1.181 +} s_FlagReader;
   1.182  
   1.183  AdminCache::AdminCache()
   1.184  {
   1.185 @@ -54,6 +227,7 @@
   1.186  	m_pAuthTables = sm_trie_create();
   1.187  	m_InvalidatingAdmins = false;
   1.188  	m_destroying = false;
   1.189 +	m_pLevelNames = sm_trie_create();
   1.190  }
   1.191  
   1.192  AdminCache::~AdminCache()
   1.193 @@ -81,6 +255,8 @@
   1.194  	sm_trie_destroy(m_pAuthTables);
   1.195  
   1.196  	delete m_pStrings;
   1.197 +
   1.198 +	sm_trie_destroy(m_pLevelNames);
   1.199  }
   1.200  
   1.201  void AdminCache::OnSourceModStartup(bool late)
   1.202 @@ -88,6 +264,28 @@
   1.203  	RegisterAuthIdentType("steam");
   1.204  	RegisterAuthIdentType("name");
   1.205  	RegisterAuthIdentType("ip");
   1.206 +
   1.207 +	NameFlag("reservation", Admin_Reservation);
   1.208 +	NameFlag("kick", Admin_Kick);
   1.209 +	NameFlag("generic", Admin_Generic);
   1.210 +	NameFlag("ban", Admin_Ban);
   1.211 +	NameFlag("unban", Admin_Unban);
   1.212 +	NameFlag("slay", Admin_Slay);
   1.213 +	NameFlag("changemap", Admin_Changemap);
   1.214 +	NameFlag("cvars", Admin_Convars);
   1.215 +	NameFlag("config", Admin_Config);
   1.216 +	NameFlag("chat", Admin_Chat);
   1.217 +	NameFlag("vote", Admin_Vote);
   1.218 +	NameFlag("password", Admin_Password);
   1.219 +	NameFlag("rcon", Admin_RCON);
   1.220 +	NameFlag("cheats", Admin_Cheats);
   1.221 +	NameFlag("root", Admin_Root);
   1.222 +	NameFlag("custom1", Admin_Custom1);
   1.223 +	NameFlag("custom2", Admin_Custom2);
   1.224 +	NameFlag("custom3", Admin_Custom3);
   1.225 +	NameFlag("custom4", Admin_Custom4);
   1.226 +	NameFlag("custom5", Admin_Custom5);
   1.227 +	NameFlag("custom6", Admin_Custom6);
   1.228  }
   1.229  
   1.230  void AdminCache::OnSourceModAllInitialized()
   1.231 @@ -96,6 +294,12 @@
   1.232  	g_ShareSys.AddInterface(NULL, this);
   1.233  }
   1.234  
   1.235 +void AdminCache::OnSourceModLevelChange(const char *mapName)
   1.236 +{
   1.237 +	/* For now, we only read these once per level. */
   1.238 +	s_FlagReader.LoadLevels();
   1.239 +}
   1.240 +
   1.241  void AdminCache::OnSourceModShutdown()
   1.242  {
   1.243  	g_Forwards.ReleaseForward(m_pCacheFwd);
   1.244 @@ -108,6 +312,27 @@
   1.245  	DumpAdminCache(AdminCache_Groups, true);
   1.246  }
   1.247  
   1.248 +void AdminCache::NameFlag(const char *str, AdminFlag flag)
   1.249 +{
   1.250 +	sm_trie_insert(m_pLevelNames, str, (void *)flag);
   1.251 +}
   1.252 +
   1.253 +bool AdminCache::FindFlag(const char *str, AdminFlag *pFlag)
   1.254 +{
   1.255 +	void *obj;
   1.256 +	if (!sm_trie_retrieve(m_pLevelNames, str, &obj))
   1.257 +	{
   1.258 +		return false;
   1.259 +	}
   1.260 +
   1.261 +	if (pFlag)
   1.262 +	{
   1.263 +		*pFlag = (AdminFlag)(int)obj;
   1.264 +	}
   1.265 +
   1.266 +	return true;
   1.267 +}
   1.268 +
   1.269  void AdminCache::AddCommandOverride(const char *cmd, OverrideType type, FlagBits flags)
   1.270  {
   1.271  	Trie *pTrie = NULL;
   1.272 @@ -1289,3 +1514,41 @@
   1.273  	
   1.274  	return true;
   1.275  }
   1.276 +
   1.277 +bool AdminCache::FindFlag(char c, AdminFlag *pAdmFlag)
   1.278 +{
   1.279 +	if (c < 'a' || c > 'z')
   1.280 +	{
   1.281 +		return false;
   1.282 +	}
   1.283 +
   1.284 +	if (*pAdmFlag)
   1.285 +	{
   1.286 +		*pAdmFlag = g_FlagLetters[(unsigned)c - (unsigned)'a'];
   1.287 +	}
   1.288 +
   1.289 +	return true;
   1.290 +}
   1.291 +
   1.292 +FlagBits AdminCache::ReadFlagString(const char *flags, const char **end)
   1.293 +{
   1.294 +	FlagBits bits = 0;
   1.295 +
   1.296 +	while (flags && (*flags != '\0'))
   1.297 +	{
   1.298 +		AdminFlag flag;
   1.299 +		if (!FindFlag(*flags, &flag))
   1.300 +		{
   1.301 +			break;
   1.302 +		}
   1.303 +		bits |= FlagArrayToBits(&flag, 1);
   1.304 +		flags++;
   1.305 +	}
   1.306 +
   1.307 +	if (end)
   1.308 +	{
   1.309 +		*end = flags;
   1.310 +	}
   1.311 +
   1.312 +	return bits;
   1.313 +}
     2.1 --- a/core/AdminCache.h	Fri Aug 10 01:07:07 2007 +0000
     2.2 +++ b/core/AdminCache.h	Fri Aug 10 04:53:30 2007 +0000
     2.3 @@ -105,6 +105,7 @@
     2.4  public: //SMGlobalClass
     2.5  	void OnSourceModStartup(bool late);
     2.6  	void OnSourceModAllInitialized();
     2.7 +	void OnSourceModLevelChange(const char *mapName);
     2.8  	void OnSourceModShutdown();
     2.9  	void OnSourceModPluginsLoaded();
    2.10  public: //IAdminSystem
    2.11 @@ -151,6 +152,9 @@
    2.12  	bool CheckAdminFlags(AdminId id, FlagBits bits);
    2.13  	bool CanAdminTarget(AdminId id, AdminId target);
    2.14  	void SetAdminFlags(AdminId id, AccessMode mode, FlagBits bits);
    2.15 +	bool FindFlag(const char *str, AdminFlag *pFlag);
    2.16 +	bool FindFlag(char c, AdminFlag *pAdmFlag);
    2.17 +	FlagBits ReadFlagString(const char *flags, const char **end);
    2.18  public:
    2.19  	bool IsValidAdmin(AdminId id);
    2.20  private:
    2.21 @@ -161,6 +165,7 @@
    2.22  	void DumpCommandOverrideCache(OverrideType type);
    2.23  	Trie *GetMethodByIndex(unsigned int index);
    2.24  	bool GetMethodIndex(const char *name, unsigned int *_index);
    2.25 +	void NameFlag(const char *str, AdminFlag flag);
    2.26  public:
    2.27  	BaseStringTable *m_pStrings;
    2.28  	BaseMemTable *m_pMemory;
    2.29 @@ -179,6 +184,7 @@
    2.30  	int m_FreeUserList;
    2.31  	bool m_InvalidatingAdmins;
    2.32  	bool m_destroying;
    2.33 +	Trie *m_pLevelNames;
    2.34  };
    2.35  
    2.36  extern AdminCache g_Admins;
     3.1 --- a/core/smn_admin.cpp	Fri Aug 10 01:07:07 2007 +0000
     3.2 +++ b/core/smn_admin.cpp	Fri Aug 10 04:53:30 2007 +0000
     3.3 @@ -451,6 +451,57 @@
     3.4  	return 1;
     3.5  }
     3.6  
     3.7 +static cell_t FindFlagByName(IPluginContext *pContext, const cell_t *params)
     3.8 +{
     3.9 +	char *flag;
    3.10 +	pContext->LocalToString(params[1], &flag);
    3.11 +
    3.12 +	cell_t *addr;
    3.13 +	pContext->LocalToPhysAddr(params[2], &addr);
    3.14 +
    3.15 +	AdminFlag admflag;
    3.16 +	if (!g_Admins.FindFlag(flag, &admflag))
    3.17 +	{
    3.18 +		return 0;
    3.19 +	}
    3.20 +
    3.21 +	*addr = (cell_t)admflag;
    3.22 +
    3.23 +	return 1;
    3.24 +}
    3.25 +
    3.26 +static cell_t FindFlagByChar(IPluginContext *pContext, const cell_t *params)
    3.27 +{
    3.28 +	cell_t *addr;
    3.29 +	pContext->LocalToPhysAddr(params[2], &addr);
    3.30 +
    3.31 +	AdminFlag admflag;
    3.32 +	if (!g_Admins.FindFlag((char)params[1], &admflag))
    3.33 +	{
    3.34 +		return 0;
    3.35 +	}
    3.36 +
    3.37 +	*addr = (cell_t)admflag;
    3.38 +
    3.39 +	return 1;
    3.40 +}
    3.41 +
    3.42 +static cell_t ReadFlagString(IPluginContext *pContext, const cell_t *params)
    3.43 +{
    3.44 +	char *flag;
    3.45 +	pContext->LocalToString(params[1], &flag);
    3.46 +
    3.47 +	cell_t *addr;
    3.48 +	pContext->LocalToPhysAddr(params[2], &addr);
    3.49 +
    3.50 +	const char *end = flag;
    3.51 +	FlagBits bits = g_Admins.ReadFlagString(flag, &end);
    3.52 +
    3.53 +	*addr = end - flag;
    3.54 +
    3.55 +	return bits;
    3.56 +}
    3.57 +
    3.58  REGISTER_NATIVES(adminNatives)
    3.59  {
    3.60  	{"DumpAdminCache",			DumpAdminCache},
    3.61 @@ -489,6 +540,9 @@
    3.62  	{"FlagBitsToArray",			FlagBitsToArray},
    3.63  	{"CanAdminTarget",			CanAdminTarget},
    3.64  	{"CreateAuthMethod",		CreateAuthMethod},
    3.65 +	{"FindFlagByName",			FindFlagByName},
    3.66 +	{"FindFlagByChar",			FindFlagByChar},
    3.67 +	{"ReadFlagString",			ReadFlagString},
    3.68  	/* -------------------------------------------------- */
    3.69  	{NULL,						NULL},
    3.70  };
     4.1 --- a/plugins/admin-flatfile/admin-flatfile.sp	Fri Aug 10 01:07:07 2007 +0000
     4.2 +++ b/plugins/admin-flatfile/admin-flatfile.sp	Fri Aug 10 04:53:30 2007 +0000
     4.3 @@ -35,14 +35,11 @@
     4.4  };
     4.5  
     4.6  /** Various parsing globals */
     4.7 -new bool:g_FlagsSet[26];					/* Maps whether flags are set */
     4.8 -new AdminFlag:g_FlagLetters[26];			/* Maps the flag letters */		
     4.9  new bool:g_LoggedFileName = false;			/* Whether or not the file name has been logged */
    4.10  new g_ErrorCount = 0;						/* Current error count */
    4.11  new g_IgnoreLevel = 0;						/* Nested ignored section count, so users can screw up files safely */
    4.12  new String:g_Filename[PLATFORM_MAX_PATH];	/* Used for error messages */
    4.13  
    4.14 -#include "admin-levels.sp"
    4.15  #include "admin-overrides.sp"
    4.16  #include "admin-groups.sp"
    4.17  #include "admin-users.sp"
    4.18 @@ -50,7 +47,6 @@
    4.19  
    4.20  public OnRebuildAdminCache(AdminCachePart:part)
    4.21  {
    4.22 -	RefreshLevels();
    4.23  	if (part == AdminCache_Overrides)
    4.24  	{
    4.25  		ReadOverrides();
     5.1 --- a/plugins/admin-flatfile/admin-groups.sp	Fri Aug 10 01:07:07 2007 +0000
     5.2 +++ b/plugins/admin-flatfile/admin-groups.sp	Fri Aug 10 04:53:30 2007 +0000
     5.3 @@ -92,15 +92,10 @@
     5.4  				new len = strlen(value);
     5.5  				for (new i=0; i<len; i++)
     5.6  				{
     5.7 -					if (value[i] < 'a' || value[i] > 'z')
     5.8 +					if (!FindFlagByChar(value[i], flag))
     5.9  					{
    5.10  						continue;
    5.11  					}
    5.12 -					if (!g_FlagsSet[value[i] - 'a'])
    5.13 -					{
    5.14 -						continue;
    5.15 -					}
    5.16 -					flag = g_FlagLetters[value[i] - 'a'];
    5.17  					SetAdmGroupAddFlag(g_CurGrp, flag, true);
    5.18  				}
    5.19  			} else if (StrEqual(key, "immunity")) {
     6.1 --- a/plugins/admin-flatfile/admin-levels.sp	Fri Aug 10 01:07:07 2007 +0000
     6.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.3 @@ -1,217 +0,0 @@
     6.4 -/* 
     6.5 - * admin-levels.sp
     6.6 - * Reads access flags from the admin_levels.cfg file.  Do not compile this directly.
     6.7 - * This file is part of SourceMod, Copyright (C) 2004-2007 AlliedModders LLC
     6.8 - *
     6.9 - * This program is free software; you can redistribute it and/or
    6.10 - * modify it under the terms of the GNU General Public License
    6.11 - * as published by the Free Software Foundation; either version 2
    6.12 - * of the License, or (at your option) any later version.
    6.13 - *
    6.14 - * This program is distributed in the hope that it will be useful,
    6.15 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
    6.16 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    6.17 - * GNU General Public License for more details.
    6.18 - * 
    6.19 - * You should have received a copy of the GNU General Public License
    6.20 - * along with this program; if not, write to the Free Software
    6.21 - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
    6.22 - *
    6.23 - * Version: $Id$
    6.24 - */
    6.25 -
    6.26 -#define LEVEL_STATE_NONE		0
    6.27 -#define LEVEL_STATE_LEVELS		1
    6.28 -#define LEVEL_STATE_FLAGS		2
    6.29 -
    6.30 -static Handle:g_hLevelParser = INVALID_HANDLE;
    6.31 -static g_LevelState = LEVEL_STATE_NONE;
    6.32 -
    6.33 -/* :TODO: log line numbers? */
    6.34 -
    6.35 -LoadDefaultLetters()
    6.36 -{
    6.37 -	for (new i='t'; i<'z'; i++)
    6.38 -	{
    6.39 -		g_FlagsSet[i-'a'] = false;
    6.40 -	}
    6.41 -	
    6.42 -	g_FlagLetters['a'-'a'] = Admin_Reservation;
    6.43 -	g_FlagLetters['b'-'a'] = Admin_Generic;
    6.44 -	g_FlagLetters['c'-'a'] = Admin_Kick;
    6.45 -	g_FlagLetters['d'-'a'] = Admin_Ban;
    6.46 -	g_FlagLetters['e'-'a'] = Admin_Unban;
    6.47 -	g_FlagLetters['f'-'a'] = Admin_Slay;
    6.48 -	g_FlagLetters['g'-'a'] = Admin_Changemap;
    6.49 -	g_FlagLetters['h'-'a'] = Admin_Convars;
    6.50 -	g_FlagLetters['i'-'a'] = Admin_Config;
    6.51 -	g_FlagLetters['j'-'a'] = Admin_Chat;
    6.52 -	g_FlagLetters['k'-'a'] = Admin_Vote;
    6.53 -	g_FlagLetters['l'-'a'] = Admin_Password;
    6.54 -	g_FlagLetters['m'-'a'] = Admin_RCON;
    6.55 -	g_FlagLetters['n'-'a'] = Admin_Cheats;
    6.56 -	g_FlagLetters['o'-'a'] = Admin_Custom1;
    6.57 -	g_FlagLetters['p'-'a'] = Admin_Custom2;
    6.58 -	g_FlagLetters['q'-'a'] = Admin_Custom3;
    6.59 -	g_FlagLetters['r'-'a'] = Admin_Custom4;
    6.60 -	g_FlagLetters['s'-'a'] = Admin_Custom5;
    6.61 -	g_FlagLetters['t'-'a'] = Admin_Custom6;
    6.62 -	g_FlagLetters['z'-'a'] = Admin_Root;
    6.63 -}
    6.64 -
    6.65 -public SMCResult:ReadLevels_NewSection(Handle:smc, const String:name[], bool:opt_quotes)
    6.66 -{
    6.67 -	if (g_IgnoreLevel)
    6.68 -	{
    6.69 -		g_IgnoreLevel++;
    6.70 -		return SMCParse_Continue;
    6.71 -	}
    6.72 -	
    6.73 -	if (g_LevelState == LEVEL_STATE_NONE)
    6.74 -	{
    6.75 -		if (StrEqual(name, "Levels"))
    6.76 -		{
    6.77 -			g_LevelState = LEVEL_STATE_LEVELS;
    6.78 -		} else {
    6.79 -			g_IgnoreLevel++;
    6.80 -		}
    6.81 -	} else if (g_LevelState == LEVEL_STATE_LEVELS) {
    6.82 -		if (StrEqual(name, "Flags"))
    6.83 -		{
    6.84 -			g_LevelState = LEVEL_STATE_FLAGS;
    6.85 -		} else {
    6.86 -			g_IgnoreLevel++;
    6.87 -		}
    6.88 -	} else {
    6.89 -		g_IgnoreLevel++;
    6.90 -	}
    6.91 -	
    6.92 -	return SMCParse_Continue;
    6.93 -}
    6.94 -
    6.95 -public SMCResult:ReadLevels_KeyValue(Handle:smc, const String:key[], const String:value[], bool:key_quotes, bool:value_quotes)
    6.96 -{
    6.97 -	if (g_LevelState == LEVEL_STATE_FLAGS && !g_IgnoreLevel)
    6.98 -	{
    6.99 -		new chr = value[0];
   6.100 -		
   6.101 -		if (chr < 'a' || chr > 'z')
   6.102 -		{
   6.103 -			ParseError("Unrecognized character: \"%s\"", value);
   6.104 -			return SMCParse_Continue;
   6.105 -		}
   6.106 -		
   6.107 -		chr -= 'a';
   6.108 -		
   6.109 -		new AdminFlag:flag;
   6.110 -		
   6.111 -		if (StrEqual(key, "reservation"))
   6.112 -		{
   6.113 -			flag = Admin_Reservation;
   6.114 -		} else if (StrEqual(key, "kick")) {
   6.115 -			flag = Admin_Kick;
   6.116 -		} else if (StrEqual(key, "generic")) {
   6.117 -			flag = Admin_Generic;
   6.118 -		} else if (StrEqual(key, "ban")) {
   6.119 -			flag = Admin_Ban;
   6.120 -		} else if (StrEqual(key, "unban")) {
   6.121 -			flag = Admin_Unban;
   6.122 -		} else if (StrEqual(key, "slay")) {
   6.123 -			flag = Admin_Slay;
   6.124 -		} else if (StrEqual(key, "changemap")) {
   6.125 -			flag = Admin_Changemap;
   6.126 -		} else if (StrEqual(key, "cvars")) {
   6.127 -			flag = Admin_Convars;
   6.128 -		} else if (StrEqual(key, "config")) {
   6.129 -			flag = Admin_Config;
   6.130 -		} else if (StrEqual(key, "chat")) {
   6.131 -			flag = Admin_Chat;
   6.132 -		} else if (StrEqual(key, "vote")) {
   6.133 -			flag = Admin_Vote;
   6.134 -		} else if (StrEqual(key, "password")) {
   6.135 -			flag = Admin_Password;
   6.136 -		} else if (StrEqual(key, "rcon")) {
   6.137 -			flag = Admin_RCON;
   6.138 -		} else if (StrEqual(key, "cheats")) {
   6.139 -			flag = Admin_Cheats;
   6.140 -		} else if (StrEqual(key, "root")) {
   6.141 -			flag = Admin_Root;
   6.142 -		} else if (StrEqual(key, "custom1")) {
   6.143 -			flag = Admin_Custom1;
   6.144 -		} else if (StrEqual(key, "custom2")) {
   6.145 -			flag = Admin_Custom2;
   6.146 -		} else if (StrEqual(key, "custom3")) {
   6.147 -			flag = Admin_Custom3;
   6.148 -		} else if (StrEqual(key, "custom4")) {
   6.149 -			flag = Admin_Custom4;
   6.150 -		} else if (StrEqual(key, "custom5")) {
   6.151 -			flag = Admin_Custom5;
   6.152 -		} else if (StrEqual(key, "custom6")) {
   6.153 -			flag = Admin_Custom6;
   6.154 -		} else {
   6.155 -			ParseError("Unrecognized flag type: %s", key);
   6.156 -		}
   6.157 -		
   6.158 -		g_FlagLetters[chr] = flag;
   6.159 -		g_FlagsSet[chr] = true;
   6.160 -	}
   6.161 -	
   6.162 -	return SMCParse_Continue;
   6.163 -}
   6.164 -
   6.165 -public SMCResult:ReadLevels_EndSection(Handle:smc)
   6.166 -{
   6.167 -	/* If we're ignoring, skip out */
   6.168 -	if (g_IgnoreLevel)
   6.169 -	{
   6.170 -		g_IgnoreLevel--;
   6.171 -		return SMCParse_Continue;
   6.172 -	}
   6.173 -	
   6.174 -	if (g_LevelState == LEVEL_STATE_FLAGS)
   6.175 -	{
   6.176 -		/* We're totally done parsing */
   6.177 -		g_LevelState = LEVEL_STATE_LEVELS;
   6.178 -		return SMCParse_Halt;
   6.179 -	} else if (g_LevelState == LEVEL_STATE_LEVELS) {
   6.180 -		g_LevelState = LEVEL_STATE_NONE;
   6.181 -	}
   6.182 -	
   6.183 -	return SMCParse_Continue;
   6.184 -}
   6.185 -
   6.186 -static InitializeLevelParser()
   6.187 -{
   6.188 -	if (g_hLevelParser == INVALID_HANDLE)
   6.189 -	{
   6.190 -		g_hLevelParser = SMC_CreateParser();
   6.191 -		SMC_SetReaders(g_hLevelParser, 
   6.192 -				   	ReadLevels_NewSection,
   6.193 -				   	ReadLevels_KeyValue,
   6.194 -				   	ReadLevels_EndSection);
   6.195 -	}
   6.196 -}
   6.197 -
   6.198 -RefreshLevels()
   6.199 -{
   6.200 -	LoadDefaultLetters();
   6.201 -	InitializeLevelParser();
   6.202 -	
   6.203 -	BuildPath(Path_SM, g_Filename, sizeof(g_Filename), "configs/admin_levels.cfg");
   6.204 -	
   6.205 -	/* Set states */
   6.206 -	InitGlobalStates();
   6.207 -	g_LevelState = LEVEL_STATE_NONE;
   6.208 -		
   6.209 -	new SMCError:err = SMC_ParseFile(g_hLevelParser, g_Filename);
   6.210 -	if (err != SMCError_Okay)
   6.211 -	{
   6.212 -		decl String:buffer[64];
   6.213 -		if (SMC_GetErrorString(err, buffer, sizeof(buffer)))
   6.214 -		{
   6.215 -			ParseError("%s", buffer);
   6.216 -		} else {
   6.217 -			ParseError("Fatal parse error");
   6.218 -		}
   6.219 -	}
   6.220 -}
     7.1 --- a/plugins/admin-flatfile/admin-overrides.sp	Fri Aug 10 01:07:07 2007 +0000
     7.2 +++ b/plugins/admin-flatfile/admin-overrides.sp	Fri Aug 10 04:53:30 2007 +0000
     7.3 @@ -69,27 +69,7 @@
     7.4  		return SMCParse_Continue;
     7.5  	}
     7.6  	
     7.7 -	new AdminFlag:array[AdminFlags_TOTAL];
     7.8 -	new flags_total;
     7.9 -	
    7.10 -	new len = strlen(value);
    7.11 -	for (new i=0; i<len; i++)
    7.12 -	{
    7.13 -		if (value[i] < 'a' || value[i] > 'z')
    7.14 -		{
    7.15 -			ParseError("Invalid flag detected: %c", value[i]);
    7.16 -			continue;
    7.17 -		}
    7.18 -		new val = value[i] - 'a';
    7.19 -		if (!g_FlagsSet[val])
    7.20 -		{
    7.21 -			ParseError("Invalid flag detected: %c", value[i]);
    7.22 -			continue;
    7.23 -		}
    7.24 -		array[flags_total++] = g_FlagLetters[val];
    7.25 -	}
    7.26 -	
    7.27 -	new flags = FlagArrayToBits(array, flags_total);
    7.28 +	new flags = ReadFlagString(value);
    7.29  	
    7.30  	if (key[0] == '@')
    7.31  	{
     8.1 --- a/plugins/admin-flatfile/admin-simple.sp	Fri Aug 10 01:07:07 2007 +0000
     8.2 +++ b/plugins/admin-flatfile/admin-simple.sp	Fri Aug 10 04:53:30 2007 +0000
     8.3 @@ -115,23 +115,19 @@
     8.4  		new bool:is_default = false;
     8.5  		for (new i=0; i<len; i++)
     8.6  		{
     8.7 -			if (flags[i] < 'a' || flags[i] > 'z')
     8.8 +			if (flags[i] == '$')
     8.9  			{
    8.10 -				if (flags[i] == '$')
    8.11 +				is_default = true;
    8.12 +			} else {
    8.13 +				new AdminFlag:flag;
    8.14 +				
    8.15 +				if (!FindFlagByChar(flags[i], flag))
    8.16  				{
    8.17 -					is_default = true;
    8.18 -				} else {
    8.19  					ParseError("Invalid flag detected: %c", flags[i]);
    8.20 +					continue;
    8.21  				}
    8.22 -				continue;
    8.23 +				SetAdminFlag(admin, flag, true);
    8.24  			}
    8.25 -			new val = flags[i] - 'a';
    8.26 -			if (!g_FlagsSet[val])
    8.27 -			{
    8.28 -				ParseError("Invalid flag detected: %c", flags[i]);
    8.29 -				continue;
    8.30 -			}
    8.31 -			SetAdminFlag(admin, g_FlagLetters[val], true);
    8.32  		}
    8.33  		
    8.34  		if (is_default)
     9.1 --- a/plugins/admin-flatfile/admin-users.sp	Fri Aug 10 01:07:07 2007 +0000
     9.2 +++ b/plugins/admin-flatfile/admin-users.sp	Fri Aug 10 04:53:30 2007 +0000
     9.3 @@ -93,21 +93,15 @@
     9.4  		}
     9.5  	} else if (StrEqual(key, "flags")) {
     9.6  		new len = strlen(value);
     9.7 +		new AdminFlag:flag;
     9.8  		
     9.9  		for (new i=0; i<len; i++)
    9.10  		{
    9.11 -			if (value[i] < 'a' || value[i] > 'z')
    9.12 +			if (!FindFlagByChar(value[i], flag))
    9.13  			{
    9.14  				ParseError("Invalid flag detected: %c", value[i]);
    9.15 -				continue;
    9.16  			}
    9.17 -			new val = value[i] - 'a';
    9.18 -			if (!g_FlagsSet[val])
    9.19 -			{
    9.20 -				ParseError("Invalid flag detected: %c", value[i]);
    9.21 -				continue;
    9.22 -			}
    9.23 -			SetAdminFlag(g_CurUser, g_FlagLetters[val], true);
    9.24 +			SetAdminFlag(g_CurUser, flag, true);
    9.25  		}
    9.26  	}
    9.27  
    10.1 --- a/plugins/include/admin.inc	Fri Aug 10 01:07:07 2007 +0000
    10.2 +++ b/plugins/include/admin.inc	Fri Aug 10 04:53:30 2007 +0000
    10.3 @@ -489,6 +489,33 @@
    10.4  native FlagBitsToArray(bits, AdminFlag:array[], maxSize);
    10.5  
    10.6  /**
    10.7 + * Finds a flag by its string name.
    10.8 + *
    10.9 + * @param name			Flag name (like "kick"), case sensitive.
   10.10 + * @param flag			Variable to store flag in.
   10.11 + * @return				True on success, false if not found.
   10.12 + */
   10.13 +native bool:FindFlagByName(const String:name[], &AdminFlag:flag);
   10.14 +
   10.15 +/**
   10.16 + * Finds a flag by a given character.
   10.17 + *
   10.18 + * @param c				Flag ASCII character/token.
   10.19 + * @param flag			Variable to store flag in.
   10.20 + * @return				True on success, false if not found.
   10.21 + */
   10.22 +native bool:FindFlagByChar(c, &AdminFlag:flag);
   10.23 +
   10.24 +/**
   10.25 + * Converts a string of flag characters to a bit string.
   10.26 + *
   10.27 + * @param flags			Flag ASCII string.
   10.28 + * @param numchars		Optional variable to store the number of bytes read.
   10.29 + * @return				Bit string of ADMFLAG values.
   10.30 + */
   10.31 +native ReadFlagString(const String:flags[], &numchars=0);
   10.32 +
   10.33 +/**
   10.34   * Tests whether one admin can target another.
   10.35   *
   10.36   * @param admin			Admin doing the targetting (may be INVALID_ADMIN_ID).
    11.1 --- a/public/IAdminSystem.h	Fri Aug 10 01:07:07 2007 +0000
    11.2 +++ b/public/IAdminSystem.h	Fri Aug 10 04:53:30 2007 +0000
    11.3 @@ -36,7 +36,7 @@
    11.4  #include <IShareSys.h>
    11.5  
    11.6  #define SMINTERFACE_ADMINSYS_NAME		"IAdminSys"
    11.7 -#define SMINTERFACE_ADMINSYS_VERSION	1
    11.8 +#define SMINTERFACE_ADMINSYS_VERSION	2
    11.9  
   11.10  /**
   11.11   * @file IAdminSystem.h
   11.12 @@ -599,6 +599,34 @@
   11.13  		 * @return			True if this admin has permission to target the other admin.
   11.14  		 */
   11.15  		virtual bool CanAdminTarget(AdminId id, AdminId target) =0;
   11.16 +
   11.17 +		/**
   11.18 +		 * @brief Returns a flag from a named string.
   11.19 +		 *
   11.20 +		 * @param flagname	Case sensitive flag name string (like "kick").
   11.21 +		 * @param pAdmFlag	Pointer to store the found admin flag in.
   11.22 +		 * @return			True on success, false on failure.
   11.23 +		 */
   11.24 +		virtual bool FindFlag(const char *flagname, AdminFlag *pAdmFlag) =0;
   11.25 +
   11.26 +		/**
   11.27 +		 * @brief Reads a single character as a flag.
   11.28 +		 *
   11.29 +		 * @param flag		Flag character.
   11.30 +		 * @param pAdmFlag	Pointer to store the admin flag.
   11.31 +		 * @return			True on success, false if invalid.
   11.32 +		 */
   11.33 +		virtual bool FindFlag(char c, AdminFlag *pAdmFlag) =0;
   11.34 +
   11.35 +		/**
   11.36 +		 * @brief Reads a string of flag letters and returns its access value.
   11.37 +		 *
   11.38 +		 * @param flags		Flag string.
   11.39 +		 * @param end		Pointer to store the last value read.  On success, 
   11.40 +		 *					this will store a pointer to the null terminator.
   11.41 +		 * @return			FlagBits value of the flags.
   11.42 +		 */
   11.43 +		virtual FlagBits ReadFlagString(const char *flags, const char **end) =0;
   11.44  	};
   11.45  }
   11.46