core/AdminCache.cpp
author David Anderson <dvander@alliedmods.net>
Sat Aug 11 18:03:55 2007 +0000 (2007-08-11)
changeset 1305 72711a64a086
parent 1299 10f58032bc78
child 1330 ab94316bb52b
permissions -rw-r--r--
fixed a bug where admin access levels were read incorrectly
dvander@370
     1
/**
ds@653
     2
 * vim: set ts=4 :
dvander@1231
     3
 * ================================================================
dvander@1231
     4
 * SourceMod
dvander@1231
     5
 * Copyright (C) 2004-2007 AlliedModders LLC.  All rights reserved.
dvander@1231
     6
 * ================================================================
dvander@370
     7
 *
dvander@1231
     8
 * This program is free software; you can redistribute it and/or 
dvander@1231
     9
 * modify it under the terms of the GNU General Public License, 
dvander@1231
    10
 * version 3.0, as published by the Free Software Foundation.
dvander@1231
    11
 * 
dvander@1231
    12
 * This program is distributed in the hope that it will be useful,
dvander@1231
    13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
dvander@1231
    14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
dvander@1231
    15
 * GNU General Public License for more details.
dvander@1231
    16
 *
dvander@1231
    17
 * You should have received a copy of the GNU General Public License
dvander@1231
    18
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
dvander@1231
    19
 *
dvander@1231
    20
 * As a special exception, AlliedModders LLC gives you permission to 
dvander@1231
    21
 * link the code of this program (as well as its derivative works) to 
dvander@1231
    22
 * "Half-Life 2," the "Source Engine," the "SourcePawn JIT," and any 
dvander@1231
    23
 * Game MODs that run on software by the Valve Corporation.  You must 
dvander@1231
    24
 * obey the GNU General Public License in all respects for all other 
dvander@1231
    25
 * code used. Additionally, AlliedModders LLC grants this exception 
dvander@1231
    26
 * to all derivative works. AlliedModders LLC defines further 
dvander@1231
    27
 * exceptions, found in LICENSE.txt (as of this writing, version 
dvander@1231
    28
 * JULY-31-2007), or <http://www.sourcemod.net/license.php>.
dvander@370
    29
 *
dvander@370
    30
 * Version: $Id$
dvander@370
    31
 */
dvander@370
    32
dvander@335
    33
#include <string.h>
dvander@335
    34
#include <assert.h>
dvander@335
    35
#include "AdminCache.h"
dvander@335
    36
#include "ShareSys.h"
dvander@336
    37
#include "ForwardSys.h"
dvander@591
    38
#include "PlayerManager.h"
dvander@583
    39
#include "ConCmdManager.h"
dvander@1298
    40
#include "TextParsers.h"
dvander@1298
    41
#include "Logger.h"
dvander@1298
    42
#include "sourcemod.h"
dvander@1298
    43
#include "sm_stringutil.h"
dvander@1298
    44
dvander@1298
    45
#define LEVEL_STATE_NONE		0
dvander@1298
    46
#define LEVEL_STATE_LEVELS		1
dvander@1298
    47
#define LEVEL_STATE_FLAGS		2
dvander@335
    48
dvander@335
    49
AdminCache g_Admins;
dvander@1298
    50
AdminFlag g_FlagLetters[26];
dvander@1298
    51
bool g_FlagSet[26];
dvander@1298
    52
dvander@1298
    53
/* Default flags */
dvander@1298
    54
AdminFlag g_DefaultFlags[26] = 
dvander@1298
    55
{
dvander@1298
    56
	Admin_Reservation, Admin_Generic, Admin_Kick, Admin_Ban, Admin_Unban,
dvander@1298
    57
	Admin_Slay, Admin_Changemap, Admin_Convars, Admin_Config, Admin_Chat,
dvander@1298
    58
	Admin_Vote, Admin_Password, Admin_RCON, Admin_Cheats, Admin_Custom1, 
dvander@1298
    59
	Admin_Custom2, Admin_Custom3, Admin_Custom4, Admin_Custom5, Admin_Custom6,
dvander@1298
    60
	Admin_Generic, Admin_Generic, Admin_Generic, Admin_Generic, Admin_Generic,
dvander@1298
    61
	Admin_Root
dvander@1298
    62
};
dvander@1298
    63
dvander@1298
    64
dvander@1298
    65
class FlagReader : public ITextListener_SMC
dvander@1298
    66
{
dvander@1298
    67
public:
dvander@1298
    68
	void LoadLevels()
dvander@1298
    69
	{
dvander@1298
    70
		if (!Parse())
dvander@1298
    71
		{
dvander@1298
    72
			memcpy(g_FlagLetters, g_DefaultFlags, sizeof(AdminFlag) * 26);
dvander@1298
    73
			for (unsigned int i=0; i<20; i++)
dvander@1298
    74
			{
dvander@1298
    75
				g_FlagSet[i] = true;
dvander@1298
    76
			}
dvander@1298
    77
			g_FlagSet[25] = true;
dvander@1298
    78
		}
dvander@1298
    79
	}
dvander@1298
    80
private:
dvander@1298
    81
	bool Parse()
dvander@1298
    82
	{
dvander@1298
    83
		unsigned int line = 0;
dvander@1298
    84
		SMCParseError error;
dvander@1298
    85
dvander@1298
    86
		m_Line = 0;
dvander@1298
    87
		m_bFileNameLogged = false;
dvander@1298
    88
		g_SourceMod.BuildPath(Path_SM, m_File, sizeof(m_File), "configs/admin_levels.cfg");
dvander@1298
    89
dvander@1298
    90
		if ((error = g_TextParser.ParseFile_SMC(m_File, this, &line, NULL))
dvander@1298
    91
			!= SMCParse_Okay)
dvander@1298
    92
		{
dvander@1298
    93
			const char *err_string = g_TextParser.GetSMCErrorString(error);
dvander@1298
    94
			if (!err_string)
dvander@1298
    95
			{
dvander@1298
    96
				err_string = "Unknown error";
dvander@1298
    97
			}
dvander@1298
    98
			ParseError("Error %d (%s)", error, err_string);
dvander@1298
    99
			return false;
dvander@1298
   100
		}
dvander@1298
   101
dvander@1298
   102
		return true;
dvander@1298
   103
	}
dvander@1298
   104
	void ReadSMC_ParseStart()
dvander@1298
   105
	{
dvander@1298
   106
		m_LevelState = LEVEL_STATE_NONE;
dvander@1298
   107
		m_IgnoreLevel = 0;
dvander@1298
   108
		memset(g_FlagSet, 0, sizeof(g_FlagSet));
dvander@1298
   109
	}
dvander@1298
   110
	SMCParseResult ReadSMC_NewSection(const char *name, bool opt_quotes)
dvander@1298
   111
	{
dvander@1298
   112
		if (m_IgnoreLevel)
dvander@1298
   113
		{
dvander@1298
   114
			m_IgnoreLevel++;
dvander@1298
   115
			return SMCParse_Continue;
dvander@1298
   116
		}
dvander@1298
   117
dvander@1298
   118
		if (m_LevelState == LEVEL_STATE_NONE)
dvander@1298
   119
		{
dvander@1298
   120
			if (strcmp(name, "Levels") == 0)
dvander@1298
   121
			{
dvander@1299
   122
				m_LevelState = LEVEL_STATE_LEVELS;
dvander@1298
   123
			} else {
dvander@1298
   124
				m_IgnoreLevel++;
dvander@1298
   125
			}
dvander@1299
   126
		} else if (m_LevelState == LEVEL_STATE_LEVELS) {
dvander@1298
   127
			if (strcmp(name, "Flags") == 0)
dvander@1298
   128
			{
dvander@1299
   129
				m_LevelState = LEVEL_STATE_FLAGS;
dvander@1298
   130
			} else {
dvander@1298
   131
				m_IgnoreLevel++;
dvander@1298
   132
			}
dvander@1298
   133
		} else {
dvander@1298
   134
			m_IgnoreLevel++;
dvander@1298
   135
		}
dvander@1298
   136
dvander@1298
   137
		return SMCParse_Continue;
dvander@1298
   138
	}
dvander@1298
   139
	SMCParseResult ReadSMC_KeyValue(const char *key, const char *value, bool key_quotes, bool value_quotes)
dvander@1298
   140
	{
dvander@1299
   141
		if (m_LevelState != LEVEL_STATE_FLAGS || m_IgnoreLevel)
dvander@1298
   142
		{
dvander@1298
   143
			return SMCParse_Continue;
dvander@1298
   144
		}
dvander@1298
   145
dvander@1298
   146
		unsigned char c = (unsigned)value[0];
dvander@1298
   147
dvander@1298
   148
		if (c < (unsigned)'a' || c > (unsigned)'z')
dvander@1298
   149
		{
dvander@1298
   150
			ParseError("Flag \"%c\" is not a lower-case ASCII letter", c);
dvander@1298
   151
			return SMCParse_Continue;
dvander@1298
   152
		}
dvander@1298
   153
dvander@1298
   154
		c -= (unsigned)'a';
dvander@1298
   155
dvander@1298
   156
		assert(c >= 0 && c < 26);
dvander@1298
   157
dvander@1298
   158
		if (!g_Admins.FindFlag(key, &g_FlagLetters[c]))
dvander@1298
   159
		{
dvander@1298
   160
			ParseError("Unrecognized admin level \"%s\"", key);
dvander@1298
   161
			return SMCParse_Continue;
dvander@1298
   162
		}
dvander@1298
   163
dvander@1298
   164
		g_FlagSet[c] = true;
dvander@1298
   165
dvander@1298
   166
		return SMCParse_Continue;
dvander@1298
   167
	}
dvander@1298
   168
	SMCParseResult ReadSMC_LeavingSection()
dvander@1298
   169
	{
dvander@1298
   170
		if (m_IgnoreLevel)
dvander@1298
   171
		{
dvander@1298
   172
			m_IgnoreLevel--;
dvander@1298
   173
			return SMCParse_Continue;
dvander@1298
   174
		}
dvander@1298
   175
dvander@1298
   176
		if (m_LevelState == LEVEL_STATE_FLAGS)
dvander@1298
   177
		{
dvander@1298
   178
			m_LevelState = LEVEL_STATE_LEVELS;
dvander@1298
   179
			return SMCParse_Halt;
dvander@1298
   180
		} else if (m_LevelState == LEVEL_STATE_LEVELS) {
dvander@1298
   181
			m_LevelState = LEVEL_STATE_NONE;
dvander@1298
   182
		}
dvander@1298
   183
dvander@1298
   184
		return SMCParse_Continue;
dvander@1298
   185
	}
dvander@1298
   186
	SMCParseResult ReadSMC_RawLine(const char *line, unsigned int curline)
dvander@1298
   187
	{
dvander@1298
   188
		m_Line = curline;
dvander@1298
   189
		return SMCParse_Continue;
dvander@1298
   190
	}
dvander@1298
   191
	void ParseError(const char *message, ...)
dvander@1298
   192
	{
dvander@1298
   193
		va_list ap;
dvander@1298
   194
		char buffer[256];
dvander@1298
   195
dvander@1298
   196
		va_start(ap, message);
dvander@1298
   197
		UTIL_FormatArgs(buffer, sizeof(buffer), message, ap);
dvander@1298
   198
		va_end(ap);
dvander@1298
   199
dvander@1298
   200
		if (!m_bFileNameLogged)
dvander@1298
   201
		{
dvander@1298
   202
			g_Logger.LogError("[SM] Parse error(s) detected in file \"%s\":", m_File);
dvander@1298
   203
			m_bFileNameLogged = true;
dvander@1298
   204
		}
dvander@1298
   205
dvander@1298
   206
		g_Logger.LogError("[SM] (Line %d): %s", m_Line, buffer);
dvander@1298
   207
	}
dvander@1298
   208
private:
dvander@1298
   209
	bool m_bFileNameLogged;
dvander@1298
   210
	char m_File[PLATFORM_MAX_PATH];
dvander@1298
   211
	int m_LevelState;
dvander@1298
   212
	int m_IgnoreLevel;
dvander@1298
   213
	unsigned int m_Line;
dvander@1298
   214
} s_FlagReader;
dvander@335
   215
dvander@335
   216
AdminCache::AdminCache()
dvander@335
   217
{
dvander@433
   218
	m_pCmdOverrides = sm_trie_create();
dvander@433
   219
	m_pCmdGrpOverrides = sm_trie_create();
dvander@335
   220
	m_pStrings = new BaseStringTable(1024);
dvander@335
   221
	m_pMemory = m_pStrings->GetMemTable();
dvander@335
   222
	m_FreeGroupList = m_FirstGroup = m_LastGroup = INVALID_GROUP_ID;
dvander@404
   223
	m_FreeUserList = m_FirstUser = m_LastUser = INVALID_ADMIN_ID;
dvander@335
   224
	m_pGroups = sm_trie_create();
dvander@336
   225
	m_pCacheFwd = NULL;
dvander@404
   226
	m_FirstGroup = -1;
dvander@405
   227
	m_pAuthTables = sm_trie_create();
dvander@458
   228
	m_InvalidatingAdmins = false;
dvander@520
   229
	m_destroying = false;
dvander@1298
   230
	m_pLevelNames = sm_trie_create();
dvander@335
   231
}
dvander@335
   232
dvander@335
   233
AdminCache::~AdminCache()
dvander@335
   234
{
dvander@520
   235
	m_destroying = true;
dvander@438
   236
	DumpAdminCache(AdminCache_Overrides, false);
dvander@438
   237
	DumpAdminCache(AdminCache_Groups, false);
dvander@438
   238
dvander@434
   239
	sm_trie_destroy(m_pCmdGrpOverrides);
dvander@434
   240
	sm_trie_destroy(m_pCmdOverrides);
dvander@335
   241
dvander@335
   242
	if (m_pGroups)
dvander@335
   243
	{
dvander@335
   244
		sm_trie_destroy(m_pGroups);
dvander@335
   245
	}
dvander@335
   246
dvander@405
   247
	List<AuthMethod>::iterator iter;
dvander@405
   248
	for (iter=m_AuthMethods.begin();
dvander@405
   249
		 iter!=m_AuthMethods.end();
dvander@405
   250
		 iter++)
dvander@405
   251
	{
dvander@405
   252
		sm_trie_destroy((*iter).table);
dvander@405
   253
	}
dvander@405
   254
dvander@405
   255
	sm_trie_destroy(m_pAuthTables);
dvander@405
   256
dvander@335
   257
	delete m_pStrings;
dvander@1298
   258
dvander@1298
   259
	sm_trie_destroy(m_pLevelNames);
dvander@335
   260
}
dvander@335
   261
dvander@404
   262
void AdminCache::OnSourceModStartup(bool late)
dvander@404
   263
{
dvander@404
   264
	RegisterAuthIdentType("steam");
dvander@404
   265
	RegisterAuthIdentType("name");
dvander@404
   266
	RegisterAuthIdentType("ip");
dvander@1298
   267
dvander@1298
   268
	NameFlag("reservation", Admin_Reservation);
dvander@1298
   269
	NameFlag("kick", Admin_Kick);
dvander@1298
   270
	NameFlag("generic", Admin_Generic);
dvander@1298
   271
	NameFlag("ban", Admin_Ban);
dvander@1298
   272
	NameFlag("unban", Admin_Unban);
dvander@1298
   273
	NameFlag("slay", Admin_Slay);
dvander@1298
   274
	NameFlag("changemap", Admin_Changemap);
dvander@1298
   275
	NameFlag("cvars", Admin_Convars);
dvander@1298
   276
	NameFlag("config", Admin_Config);
dvander@1298
   277
	NameFlag("chat", Admin_Chat);
dvander@1298
   278
	NameFlag("vote", Admin_Vote);
dvander@1298
   279
	NameFlag("password", Admin_Password);
dvander@1298
   280
	NameFlag("rcon", Admin_RCON);
dvander@1298
   281
	NameFlag("cheats", Admin_Cheats);
dvander@1298
   282
	NameFlag("root", Admin_Root);
dvander@1298
   283
	NameFlag("custom1", Admin_Custom1);
dvander@1298
   284
	NameFlag("custom2", Admin_Custom2);
dvander@1298
   285
	NameFlag("custom3", Admin_Custom3);
dvander@1298
   286
	NameFlag("custom4", Admin_Custom4);
dvander@1298
   287
	NameFlag("custom5", Admin_Custom5);
dvander@1298
   288
	NameFlag("custom6", Admin_Custom6);
dvander@404
   289
}
dvander@404
   290
dvander@335
   291
void AdminCache::OnSourceModAllInitialized()
dvander@335
   292
{
dvander@336
   293
	m_pCacheFwd = g_Forwards.CreateForward("OnRebuildAdminCache", ET_Ignore, 1, NULL, Param_Cell);
dvander@335
   294
	g_ShareSys.AddInterface(NULL, this);
dvander@335
   295
}
dvander@335
   296
dvander@1298
   297
void AdminCache::OnSourceModLevelChange(const char *mapName)
dvander@1298
   298
{
dvander@1298
   299
	/* For now, we only read these once per level. */
dvander@1298
   300
	s_FlagReader.LoadLevels();
dvander@1298
   301
}
dvander@1298
   302
dvander@336
   303
void AdminCache::OnSourceModShutdown()
dvander@336
   304
{
dvander@336
   305
	g_Forwards.ReleaseForward(m_pCacheFwd);
dvander@336
   306
	m_pCacheFwd = NULL;
dvander@336
   307
}
dvander@336
   308
dvander@673
   309
void AdminCache::OnSourceModPluginsLoaded()
dvander@673
   310
{
dvander@673
   311
	DumpAdminCache(AdminCache_Overrides, true);
dvander@673
   312
	DumpAdminCache(AdminCache_Groups, true);
dvander@673
   313
}
dvander@673
   314
dvander@1298
   315
void AdminCache::NameFlag(const char *str, AdminFlag flag)
dvander@1298
   316
{
dvander@1298
   317
	sm_trie_insert(m_pLevelNames, str, (void *)flag);
dvander@1298
   318
}
dvander@1298
   319
dvander@1298
   320
bool AdminCache::FindFlag(const char *str, AdminFlag *pFlag)
dvander@1298
   321
{
dvander@1298
   322
	void *obj;
dvander@1298
   323
	if (!sm_trie_retrieve(m_pLevelNames, str, &obj))
dvander@1298
   324
	{
dvander@1298
   325
		return false;
dvander@1298
   326
	}
dvander@1298
   327
dvander@1298
   328
	if (pFlag)
dvander@1298
   329
	{
dvander@1298
   330
		*pFlag = (AdminFlag)(int)obj;
dvander@1298
   331
	}
dvander@1298
   332
dvander@1298
   333
	return true;
dvander@1298
   334
}
dvander@1298
   335
dvander@433
   336
void AdminCache::AddCommandOverride(const char *cmd, OverrideType type, FlagBits flags)
dvander@335
   337
{
dvander@433
   338
	Trie *pTrie = NULL;
dvander@335
   339
	if (type == Override_Command)
dvander@335
   340
	{
dvander@433
   341
		pTrie = m_pCmdOverrides;
dvander@335
   342
	} else if (type == Override_CommandGroup) {
dvander@433
   343
		pTrie = m_pCmdGrpOverrides;
dvander@433
   344
	} else {
dvander@433
   345
		return;
dvander@335
   346
	}
dvander@433
   347
dvander@433
   348
	sm_trie_insert(pTrie, cmd, (void *)(unsigned int)flags);
dvander@514
   349
dvander@514
   350
	g_ConCmds.UpdateAdminCmdFlags(cmd, type, flags);
dvander@335
   351
}
dvander@335
   352
dvander@433
   353
bool AdminCache::GetCommandOverride(const char *cmd, OverrideType type, FlagBits *pFlags)
dvander@335
   354
{
dvander@433
   355
	Trie *pTrie = NULL;
dvander@433
   356
dvander@335
   357
	if (type == Override_Command)
dvander@335
   358
	{
dvander@433
   359
		pTrie = m_pCmdOverrides;
dvander@335
   360
	} else if (type == Override_CommandGroup) {
dvander@433
   361
		pTrie = m_pCmdGrpOverrides;
dvander@433
   362
	} else {
dvander@433
   363
		return false;
dvander@433
   364
	}
dvander@433
   365
dvander@433
   366
	void *object;
dvander@433
   367
	if (sm_trie_retrieve(pTrie, cmd, &object))
dvander@433
   368
	{
dvander@433
   369
		if (pFlags)
dvander@433
   370
		{
dvander@433
   371
			*pFlags = (FlagBits)object;
dvander@433
   372
		}
dvander@433
   373
		return true;
dvander@335
   374
	}
dvander@335
   375
dvander@335
   376
	return false;
dvander@335
   377
}
dvander@335
   378
dvander@335
   379
void AdminCache::UnsetCommandOverride(const char *cmd, OverrideType type)
dvander@335
   380
{
dvander@335
   381
	if (type == Override_Command)
dvander@335
   382
	{
dvander@335
   383
		return _UnsetCommandOverride(cmd);
dvander@335
   384
	} else if (type == Override_CommandGroup) {
dvander@335
   385
		return _UnsetCommandGroupOverride(cmd);
dvander@335
   386
	}
dvander@335
   387
}
dvander@335
   388
dvander@335
   389
void AdminCache::_UnsetCommandGroupOverride(const char *group)
dvander@335
   390
{
dvander@335
   391
	if (!m_pCmdGrpOverrides)
dvander@335
   392
	{
dvander@335
   393
		return;
dvander@335
   394
	}
dvander@335
   395
dvander@514
   396
	sm_trie_delete(m_pCmdGrpOverrides, group);
dvander@335
   397
dvander@514
   398
	g_ConCmds.UpdateAdminCmdFlags(group, Override_CommandGroup, 0);
dvander@335
   399
}
dvander@335
   400
dvander@335
   401
void AdminCache::_UnsetCommandOverride(const char *cmd)
dvander@335
   402
{
dvander@335
   403
	if (!m_pCmdOverrides)
dvander@335
   404
	{
dvander@335
   405
		return;
dvander@335
   406
	}
dvander@335
   407
dvander@514
   408
	sm_trie_delete(m_pCmdOverrides, cmd);
dvander@335
   409
dvander@514
   410
	g_ConCmds.UpdateAdminCmdFlags(cmd, Override_Command, 0);
dvander@335
   411
}
dvander@335
   412
dvander@335
   413
void AdminCache::DumpCommandOverrideCache(OverrideType type)
dvander@335
   414
{
dvander@335
   415
	if (type == Override_Command && m_pCmdOverrides)
dvander@335
   416
	{
dvander@335
   417
		sm_trie_clear(m_pCmdOverrides);
dvander@335
   418
	} else if (type == Override_CommandGroup && m_pCmdGrpOverrides) {
dvander@335
   419
		sm_trie_clear(m_pCmdGrpOverrides);
dvander@335
   420
	}
dvander@335
   421
}
dvander@335
   422
dvander@404
   423
AdminId AdminCache::CreateAdmin(const char *name)
dvander@404
   424
{
dvander@404
   425
	AdminId id;
dvander@404
   426
	AdminUser *pUser;
dvander@404
   427
dvander@404
   428
	if (m_FreeUserList != INVALID_ADMIN_ID)
dvander@404
   429
	{
dvander@404
   430
		pUser = (AdminUser *)m_pMemory->GetAddress(m_FreeUserList);
dvander@404
   431
		assert(pUser->magic == USR_MAGIC_UNSET);
dvander@404
   432
		id = m_FreeUserList;
dvander@404
   433
		m_FreeUserList = pUser->next_user;
dvander@404
   434
	} else {
dvander@404
   435
		id = m_pMemory->CreateMem(sizeof(AdminUser), (void **)&pUser);
dvander@404
   436
		pUser->grp_size = 0;
dvander@404
   437
		pUser->grp_table = -1;
dvander@404
   438
	}
dvander@404
   439
dvander@433
   440
	pUser->flags = 0;
dvander@433
   441
	pUser->eflags = 0;
dvander@404
   442
	pUser->grp_count = 0;
dvander@404
   443
	pUser->password = -1;
dvander@404
   444
	pUser->magic = USR_MAGIC_SET;
dvander@405
   445
	pUser->auth.identidx = -1;
dvander@405
   446
	pUser->auth.index = 0;
dvander@434
   447
	pUser->immune_default = false;
dvander@434
   448
	pUser->immune_global = false;
dvander@404
   449
dvander@404
   450
	if (m_FirstUser == INVALID_ADMIN_ID)
dvander@404
   451
	{
dvander@404
   452
		m_FirstUser = id;
dvander@404
   453
		m_LastUser = id;
dvander@404
   454
	} else {
dvander@404
   455
		AdminUser *pPrev = (AdminUser *)m_pMemory->GetAddress(m_LastUser);
dvander@404
   456
		pPrev->next_user = id;
dvander@404
   457
		pUser->prev_user = m_LastUser;
dvander@404
   458
		m_LastUser = id;
dvander@404
   459
	}
dvander@404
   460
dvander@404
   461
	if (name && name[0] != '\0')
dvander@404
   462
	{
dvander@404
   463
		pUser->nameidx = m_pStrings->AddString(name);
dvander@404
   464
	}
dvander@404
   465
dvander@404
   466
	return id;
dvander@404
   467
}
dvander@404
   468
dvander@335
   469
GroupId AdminCache::AddGroup(const char *group_name)
dvander@335
   470
{
dvander@335
   471
	if (sm_trie_retrieve(m_pGroups, group_name, NULL))
dvander@335
   472
	{
dvander@335
   473
		return INVALID_GROUP_ID;
dvander@335
   474
	}
dvander@335
   475
dvander@335
   476
	GroupId id;
dvander@335
   477
	AdminGroup *pGroup;
dvander@335
   478
	if (m_FreeGroupList != INVALID_GROUP_ID)
dvander@335
   479
	{
dvander@335
   480
		pGroup = (AdminGroup *)m_pMemory->GetAddress(m_FreeGroupList);
dvander@335
   481
		assert(pGroup->magic == GRP_MAGIC_UNSET);
dvander@335
   482
		id = m_FreeGroupList;
dvander@335
   483
		m_FreeGroupList = pGroup->next_grp;
dvander@335
   484
	} else {
dvander@335
   485
		id = m_pMemory->CreateMem(sizeof(AdminGroup), (void **)&pGroup);
dvander@335
   486
	}
dvander@335
   487
dvander@335
   488
	pGroup->immune_default = false;
dvander@335
   489
	pGroup->immune_global = false;
dvander@335
   490
	pGroup->immune_table = -1;
dvander@335
   491
	pGroup->magic = GRP_MAGIC_SET;
dvander@335
   492
	pGroup->next_grp = INVALID_GROUP_ID;
dvander@335
   493
	pGroup->pCmdGrpTable = NULL;
dvander@335
   494
	pGroup->pCmdTable = NULL;
dvander@433
   495
	pGroup->addflags = 0;
dvander@335
   496
dvander@335
   497
	if (m_FirstGroup == INVALID_GROUP_ID)
dvander@335
   498
	{
dvander@335
   499
		m_FirstGroup = id;
dvander@335
   500
		m_LastGroup = id;
dvander@335
   501
		pGroup->prev_grp = INVALID_GROUP_ID;
dvander@335
   502
	} else {
dvander@335
   503
		AdminGroup *pPrev = (AdminGroup *)m_pMemory->GetAddress(m_LastGroup);
dvander@335
   504
		assert(pPrev->magic == GRP_MAGIC_SET);
dvander@335
   505
		pPrev->next_grp = id;
dvander@335
   506
		pGroup->prev_grp = m_LastGroup;
dvander@335
   507
		m_LastGroup = id;
dvander@335
   508
	}
dvander@335
   509
dvander@404
   510
	pGroup->nameidx = m_pStrings->AddString(group_name);
dvander@404
   511
dvander@335
   512
	sm_trie_insert(m_pGroups, group_name, (void *)id);
dvander@335
   513
dvander@335
   514
	return id;
dvander@335
   515
}
dvander@335
   516
dvander@335
   517
GroupId AdminCache::FindGroupByName(const char *group_name)
dvander@335
   518
{
dvander@335
   519
	void *object;
dvander@335
   520
dvander@335
   521
	if (!sm_trie_retrieve(m_pGroups, group_name, &object))
dvander@335
   522
	{
dvander@335
   523
		return INVALID_GROUP_ID;
dvander@335
   524
	}
dvander@335
   525
dvander@335
   526
	GroupId id = (GroupId)object;
dvander@335
   527
	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
dvander@335
   528
dvander@335
   529
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@335
   530
	{
dvander@335
   531
		return INVALID_GROUP_ID;
dvander@335
   532
	}
dvander@335
   533
dvander@335
   534
	return id;
dvander@335
   535
}
dvander@335
   536
dvander@335
   537
void AdminCache::SetGroupAddFlag(GroupId id, AdminFlag flag, bool enabled)
dvander@335
   538
{
dvander@335
   539
	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
dvander@335
   540
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@335
   541
	{
dvander@335
   542
		return;
dvander@335
   543
	}
dvander@335
   544
dvander@433
   545
	if (flag < Admin_Reservation || flag >= AdminFlags_TOTAL)
dvander@335
   546
	{
dvander@335
   547
		return;
dvander@335
   548
	}
dvander@335
   549
dvander@436
   550
	FlagBits bits = (1<<(FlagBits)flag);
dvander@436
   551
dvander@436
   552
	if (enabled)
dvander@436
   553
	{
dvander@436
   554
		pGroup->addflags |= bits;
dvander@436
   555
	} else {
dvander@436
   556
		pGroup->addflags &= ~bits;
dvander@436
   557
	}
dvander@335
   558
}
dvander@335
   559
dvander@335
   560
bool AdminCache::GetGroupAddFlag(GroupId id, AdminFlag flag)
dvander@335
   561
{
dvander@335
   562
	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
dvander@335
   563
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@335
   564
	{
dvander@335
   565
		return false;
dvander@335
   566
	}
dvander@335
   567
dvander@433
   568
	if (flag < Admin_Reservation || flag >= AdminFlags_TOTAL)
dvander@335
   569
	{
dvander@335
   570
		return false;
dvander@335
   571
	}
dvander@335
   572
dvander@433
   573
	FlagBits bit = 1<<(FlagBits)flag;
dvander@433
   574
	return ((pGroup->addflags & bit) == bit);
dvander@335
   575
}
dvander@335
   576
dvander@433
   577
FlagBits AdminCache::GetGroupAddFlags(GroupId id)
dvander@335
   578
{
dvander@335
   579
	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
dvander@335
   580
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@335
   581
	{
dvander@335
   582
		return 0;
dvander@335
   583
	}
dvander@335
   584
dvander@433
   585
	return pGroup->addflags;
dvander@335
   586
}
dvander@335
   587
dvander@335
   588
void AdminCache::SetGroupGenericImmunity(GroupId id, ImmunityType type, bool enabled)
dvander@335
   589
{
dvander@335
   590
	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
dvander@335
   591
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@335
   592
	{
dvander@335
   593
		return;
dvander@335
   594
	}
dvander@335
   595
dvander@335
   596
	if (type == Immunity_Default)
dvander@335
   597
	{
dvander@335
   598
		pGroup->immune_default = enabled;
dvander@335
   599
	} else if (type == Immunity_Global) {
dvander@335
   600
		pGroup->immune_global = enabled;
dvander@335
   601
	} 
dvander@335
   602
}
dvander@335
   603
dvander@335
   604
bool AdminCache::GetGroupGenericImmunity(GroupId id, ImmunityType type)
dvander@335
   605
{
dvander@335
   606
	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
dvander@335
   607
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@335
   608
	{
dvander@335
   609
		return false;
dvander@335
   610
	}
dvander@335
   611
dvander@335
   612
	if (type == Immunity_Default)
dvander@335
   613
	{
dvander@335
   614
		return pGroup->immune_default;
dvander@335
   615
	} else if (type == Immunity_Global) {
dvander@335
   616
		return pGroup->immune_global;
dvander@335
   617
	}
dvander@335
   618
dvander@335
   619
	return false;
dvander@335
   620
}
dvander@335
   621
dvander@335
   622
void AdminCache::AddGroupImmunity(GroupId id, GroupId other_id)
dvander@335
   623
{
dvander@335
   624
	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
dvander@335
   625
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@335
   626
	{
dvander@335
   627
		return;
dvander@335
   628
	}
dvander@335
   629
dvander@335
   630
	AdminGroup *pOther = (AdminGroup *)m_pMemory->GetAddress(id);
dvander@335
   631
	if (!pOther || pOther->magic != GRP_MAGIC_SET)
dvander@335
   632
	{
dvander@335
   633
		return;
dvander@335
   634
	}
dvander@335
   635
dvander@335
   636
	/* We always need to resize the immunity table */
dvander@335
   637
	int *table, tblidx;
dvander@335
   638
	if (pOther->immune_table == -1)
dvander@335
   639
	{
dvander@335
   640
		tblidx = m_pMemory->CreateMem(sizeof(int) * 2, (void **)&table);
dvander@335
   641
		table[0] = 0;
dvander@335
   642
	} else {
dvander@335
   643
		int *old_table = (int *)m_pMemory->GetAddress(pOther->immune_table);
dvander@433
   644
		/* Break out if this group is already in the list */
dvander@433
   645
		for (int i=0; i<old_table[0]; i++)
dvander@433
   646
		{
dvander@433
   647
			if (old_table[1+i] == other_id)
dvander@433
   648
			{
dvander@433
   649
				return;
dvander@433
   650
			}
dvander@433
   651
		}
dvander@335
   652
		tblidx = m_pMemory->CreateMem(sizeof(int) * (old_table[0] + 2), (void **)&table);
dvander@433
   653
		/* Get the old address again in case of resize */
dvander@335
   654
		old_table = (int *)m_pMemory->GetAddress(pOther->immune_table);
dvander@335
   655
		table[0] = old_table[0];
dvander@335
   656
		for (unsigned int i=1; i<=(unsigned int)old_table[0]; i++)
dvander@335
   657
		{
dvander@335
   658
			table[i] = old_table[i];
dvander@335
   659
		}
dvander@335
   660
	}
dvander@335
   661
dvander@335
   662
	/* Assign */
dvander@335
   663
	pOther->immune_table = tblidx;
dvander@335
   664
dvander@335
   665
	/* Add to the array */
dvander@335
   666
	table[0]++;
dvander@335
   667
	table[table[0]] = other_id;
dvander@335
   668
}
dvander@335
   669
dvander@335
   670
unsigned int AdminCache::GetGroupImmunityCount(GroupId id)
dvander@335
   671
{
dvander@335
   672
	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
dvander@335
   673
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@335
   674
	{
dvander@335
   675
		return 0;
dvander@335
   676
	}
dvander@335
   677
dvander@335
   678
	if (pGroup->immune_table == -1)
dvander@335
   679
	{
dvander@335
   680
		return 0;
dvander@335
   681
	}
dvander@335
   682
dvander@335
   683
	int *table = (int *)m_pMemory->GetAddress(pGroup->immune_table);
dvander@335
   684
dvander@335
   685
	return table[0];
dvander@335
   686
}
dvander@335
   687
dvander@335
   688
GroupId AdminCache::GetGroupImmunity(GroupId id, unsigned int number)
dvander@335
   689
{
dvander@335
   690
	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
dvander@335
   691
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@335
   692
	{
dvander@335
   693
		return INVALID_GROUP_ID;
dvander@335
   694
	}
dvander@335
   695
dvander@335
   696
	if (pGroup->immune_table == -1)
dvander@335
   697
	{
dvander@335
   698
		return INVALID_GROUP_ID;
dvander@335
   699
	}
dvander@335
   700
dvander@335
   701
	int *table = (int *)m_pMemory->GetAddress(pGroup->immune_table);
dvander@335
   702
	if (number >= (unsigned int)table[0])
dvander@335
   703
	{
dvander@335
   704
		return INVALID_GROUP_ID;
dvander@335
   705
	}
dvander@335
   706
dvander@335
   707
	return table[1 + number];
dvander@335
   708
}
dvander@335
   709
dvander@335
   710
void AdminCache::AddGroupCommandOverride(GroupId id, const char *name, OverrideType type, OverrideRule rule)
dvander@335
   711
{
dvander@335
   712
	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
dvander@335
   713
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@335
   714
	{
dvander@335
   715
		return;
dvander@335
   716
	}
dvander@335
   717
dvander@335
   718
	Trie *pTrie = NULL;
dvander@335
   719
	if (type == Override_Command)
dvander@335
   720
	{
dvander@335
   721
		if (pGroup->pCmdTable == NULL)
dvander@335
   722
		{
dvander@335
   723
			pGroup->pCmdTable = sm_trie_create();
dvander@335
   724
		}
dvander@335
   725
		pTrie = pGroup->pCmdTable;
dvander@335
   726
	} else if (type == Override_CommandGroup) {
dvander@335
   727
		if (pGroup->pCmdGrpTable == NULL)
dvander@335
   728
		{
dvander@335
   729
			pGroup->pCmdGrpTable = sm_trie_create();
dvander@335
   730
		}
dvander@335
   731
		pTrie = pGroup->pCmdGrpTable;
dvander@335
   732
	} else {
dvander@335
   733
		return;
dvander@335
   734
	}
dvander@335
   735
dvander@335
   736
	sm_trie_insert(pTrie, name, (void *)(int)rule);
dvander@335
   737
}
dvander@335
   738
dvander@335
   739
bool AdminCache::GetGroupCommandOverride(GroupId id, const char *name, OverrideType type, OverrideRule *pRule)
dvander@335
   740
{
dvander@335
   741
	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
dvander@335
   742
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@335
   743
	{
dvander@335
   744
		return false;
dvander@335
   745
	}
dvander@335
   746
dvander@335
   747
	Trie *pTrie = NULL;
dvander@335
   748
	if (type == Override_Command)
dvander@335
   749
	{
dvander@335
   750
		if (pGroup->pCmdTable == NULL)
dvander@335
   751
		{
dvander@335
   752
			return false;
dvander@335
   753
		}
dvander@335
   754
		pTrie = pGroup->pCmdTable;
dvander@335
   755
	} else if (type == Override_CommandGroup) {
dvander@335
   756
		if (pGroup->pCmdGrpTable == NULL)
dvander@335
   757
		{
dvander@335
   758
			return false;
dvander@335
   759
		}
dvander@335
   760
		pTrie = pGroup->pCmdGrpTable;
dvander@335
   761
	} else {
dvander@335
   762
		return false;
dvander@335
   763
	}
dvander@335
   764
dvander@335
   765
	void *object;
dvander@335
   766
	if (!sm_trie_retrieve(pTrie, name, &object))
dvander@335
   767
	{
dvander@335
   768
		return false;
dvander@335
   769
	}
dvander@335
   770
dvander@335
   771
	if (pRule)
dvander@335
   772
	{
dvander@335
   773
		*pRule = (OverrideRule)(int)object;
dvander@335
   774
	}
dvander@335
   775
	
dvander@335
   776
	return true;
dvander@335
   777
}
dvander@335
   778
dvander@404
   779
Trie *AdminCache::GetMethodByIndex(unsigned int index)
dvander@404
   780
{
dvander@404
   781
	List<AuthMethod>::iterator iter;
dvander@404
   782
	for (iter=m_AuthMethods.begin();
dvander@404
   783
		 iter!=m_AuthMethods.end();
dvander@404
   784
		 iter++)
dvander@404
   785
	{
dvander@404
   786
		if (index-- == 0)
dvander@404
   787
		{
dvander@404
   788
			return (*iter).table;
dvander@404
   789
		}
dvander@404
   790
	}
dvander@404
   791
dvander@404
   792
	return NULL;
dvander@404
   793
}
dvander@404
   794
dvander@404
   795
bool AdminCache::InvalidateAdmin(AdminId id)
dvander@404
   796
{
dvander@404
   797
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@404
   798
	AdminUser *pOther;
dvander@404
   799
	if (!pUser || pUser->magic != USR_MAGIC_SET)
dvander@404
   800
	{
dvander@404
   801
		return false;
dvander@404
   802
	}
dvander@404
   803
dvander@520
   804
	if (!m_InvalidatingAdmins && !m_destroying)
dvander@458
   805
	{
dvander@458
   806
		g_Players.ClearAdminId(id);
dvander@458
   807
	}
dvander@458
   808
dvander@404
   809
	/* Unlink from the dbl link list */
dvander@404
   810
	if (id == m_FirstUser && id == m_LastUser)
dvander@404
   811
	{
dvander@404
   812
		m_FirstUser = INVALID_ADMIN_ID;
dvander@404
   813
		m_LastUser = INVALID_ADMIN_ID;
dvander@404
   814
	} else if (id == m_FirstUser) {
dvander@404
   815
		m_FirstUser = pUser->next_user;
dvander@404
   816
		pOther = (AdminUser *)m_pMemory->GetAddress(m_FirstUser);
dvander@404
   817
		pOther->prev_user = INVALID_ADMIN_ID;
dvander@404
   818
	} else if (id == m_LastUser) {
dvander@404
   819
		m_LastUser = pUser->prev_user;
dvander@404
   820
		pOther = (AdminUser *)m_pMemory->GetAddress(m_LastUser);
dvander@404
   821
		pOther->next_user = INVALID_ADMIN_ID;
dvander@404
   822
	} else {
dvander@404
   823
		pOther = (AdminUser *)m_pMemory->GetAddress(pUser->prev_user);
dvander@404
   824
		pOther->next_user = pUser->next_user;
dvander@404
   825
		pOther = (AdminUser *)m_pMemory->GetAddress(pUser->next_user);
dvander@404
   826
		pOther->prev_user = pUser->prev_user;
dvander@404
   827
	}
dvander@404
   828
dvander@404
   829
	/* Unlink from auth tables */
dvander@405
   830
	if (pUser->auth.identidx != -1)
dvander@404
   831
	{
dvander@405
   832
		Trie *pTrie = GetMethodByIndex(pUser->auth.index);
dvander@405
   833
		if (pTrie)
dvander@404
   834
		{
dvander@405
   835
			sm_trie_delete(pTrie, m_pStrings->GetString(pUser->auth.identidx));
dvander@404
   836
		}
dvander@404
   837
	}
dvander@404
   838
dvander@404
   839
	/* Clear table counts */
dvander@404
   840
	pUser->grp_count = 0;
dvander@405
   841
	
dvander@404
   842
	/* Link into free list */
dvander@404
   843
	pUser->magic = USR_MAGIC_UNSET;
dvander@404
   844
	pUser->next_user = m_FreeUserList;
dvander@404
   845
	m_FreeUserList = id;
dvander@404
   846
dvander@404
   847
	return true;
dvander@404
   848
}
dvander@404
   849
dvander@404
   850
dvander@335
   851
void AdminCache::InvalidateGroup(GroupId id)
dvander@335
   852
{
dvander@335
   853
	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
dvander@335
   854
	AdminGroup *pOther;
dvander@335
   855
dvander@335
   856
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@335
   857
	{
dvander@335
   858
		return;
dvander@335
   859
	}
dvander@335
   860
dvander@335
   861
	const char *str = m_pStrings->GetString(pGroup->nameidx);
dvander@335
   862
	sm_trie_delete(m_pGroups, str);
dvander@335
   863
dvander@335
   864
	/* Unlink from the live dbllink list */
dvander@335
   865
	if (id == m_FirstGroup && id == m_LastGroup)
dvander@335
   866
	{
dvander@335
   867
		m_LastGroup = INVALID_GROUP_ID;
dvander@335
   868
		m_FirstGroup = INVALID_GROUP_ID;
dvander@335
   869
	} else if (id == m_FirstGroup) {
dvander@335
   870
		m_FirstGroup = pGroup->next_grp;
dvander@335
   871
		pOther = (AdminGroup *)m_pMemory->GetAddress(m_FirstGroup);
dvander@335
   872
		pOther->prev_grp = INVALID_GROUP_ID;
dvander@335
   873
	} else if (id == m_LastGroup) {
dvander@335
   874
		m_LastGroup = pGroup->prev_grp;
dvander@335
   875
		pOther = (AdminGroup *)m_pMemory->GetAddress(m_LastGroup);
dvander@335
   876
		pOther->next_grp = INVALID_GROUP_ID;
dvander@335
   877
	} else {
dvander@335
   878
		pOther = (AdminGroup *)m_pMemory->GetAddress(pGroup->prev_grp);
dvander@335
   879
		pOther->next_grp = pGroup->next_grp;
dvander@335
   880
		pOther = (AdminGroup *)m_pMemory->GetAddress(pGroup->next_grp);
dvander@335
   881
		pOther->prev_grp = pGroup->prev_grp;
dvander@335
   882
	}
dvander@335
   883
dvander@335
   884
	/* Free any used memory to be safe */
dvander@335
   885
	if (pGroup->pCmdGrpTable)
dvander@335
   886
	{
dvander@335
   887
		sm_trie_destroy(pGroup->pCmdGrpTable);
dvander@335
   888
		pGroup->pCmdGrpTable = NULL;
dvander@335
   889
	}
dvander@335
   890
	if (pGroup->pCmdTable)
dvander@335
   891
	{
dvander@335
   892
		sm_trie_destroy(pGroup->pCmdTable);
dvander@335
   893
		pGroup->pCmdTable = NULL;
dvander@335
   894
	}
dvander@335
   895
dvander@335
   896
	/* Link into the free list */
dvander@335
   897
	pGroup->magic = GRP_MAGIC_UNSET;
dvander@335
   898
	pGroup->next_grp = m_FreeGroupList;
dvander@335
   899
	m_FreeGroupList = id;
dvander@335
   900
dvander@404
   901
	int idx = m_FirstUser;
dvander@404
   902
	AdminUser *pUser;
dvander@404
   903
	int *table;
dvander@404
   904
	while (idx != INVALID_ADMIN_ID)
dvander@404
   905
	{
dvander@404
   906
		pUser = (AdminUser *)m_pMemory->GetAddress(idx);
dvander@404
   907
		if (pUser->grp_count > 0)
dvander@404
   908
		{
dvander@404
   909
			table = (int *)m_pMemory->GetAddress(pUser->grp_table);
dvander@404
   910
			for (unsigned int i=0; i<pUser->grp_count; i++)
dvander@404
   911
			{
dvander@404
   912
				if (table[i] == id)
dvander@404
   913
				{
dvander@404
   914
					/* We have to remove this entry */
dvander@404
   915
					for (unsigned int j=i+1; j<pUser->grp_count; j++)
dvander@404
   916
					{
dvander@404
   917
						/* Move everything down by one */
dvander@404
   918
						table[j-1] = table[j];
dvander@404
   919
					}
dvander@404
   920
					/* Decrease count */
dvander@404
   921
					pUser->grp_count--;
dvander@404
   922
					/* Recalculate effective flags */
dvander@433
   923
					pUser->eflags = pUser->flags;
dvander@404
   924
					for (unsigned int j=0; j<pUser->grp_count; j++)
dvander@404
   925
					{
dvander@404
   926
						pOther = (AdminGroup *)m_pMemory->GetAddress(table[j]);
dvander@433
   927
						pUser->eflags |= pOther->addflags;
dvander@404
   928
					}
dvander@404
   929
					/* Break now, duplicates aren't allowed */
dvander@404
   930
					break;
dvander@404
   931
				}
dvander@404
   932
			}
dvander@404
   933
		}
dvander@404
   934
		idx = pUser->next_user;
dvander@404
   935
	}
dvander@335
   936
}
dvander@335
   937
dvander@335
   938
void AdminCache::InvalidateGroupCache()
dvander@335
   939
{
dvander@335
   940
	/* Nuke the free list */
dvander@335
   941
	m_FreeGroupList = -1;
dvander@335
   942
dvander@335
   943
	/* Nuke reverse lookups */
dvander@335
   944
	sm_trie_clear(m_pGroups);
dvander@335
   945
dvander@335
   946
	/* Free memory on groups */
dvander@335
   947
	GroupId cur = m_FirstGroup;
dvander@335
   948
	AdminGroup *pGroup;
dvander@335
   949
	while (cur != INVALID_GROUP_ID)
dvander@335
   950
	{
dvander@335
   951
		pGroup = (AdminGroup *)m_pMemory->GetAddress(cur);
dvander@335
   952
		assert(pGroup->magic == GRP_MAGIC_SET);
dvander@335
   953
		if (pGroup->pCmdGrpTable)
dvander@335
   954
		{
dvander@335
   955
			sm_trie_destroy(pGroup->pCmdGrpTable);
dvander@335
   956
		}
dvander@335
   957
		if (pGroup->pCmdTable)
dvander@335
   958
		{
dvander@335
   959
			sm_trie_destroy(pGroup->pCmdTable);
dvander@335
   960
		}
dvander@335
   961
		cur = pGroup->next_grp;
dvander@335
   962
	}
dvander@335
   963
dvander@335
   964
	m_FirstGroup = INVALID_GROUP_ID;
dvander@335
   965
	m_LastGroup = INVALID_GROUP_ID;
dvander@335
   966
dvander@404
   967
	InvalidateAdminCache(false);
dvander@335
   968
dvander@335
   969
	/* Reset the memory table */
dvander@335
   970
	m_pMemory->Reset();
dvander@335
   971
}
dvander@336
   972
dvander@336
   973
void AdminCache::AddAdminListener(IAdminListener *pListener)
dvander@336
   974
{
dvander@336
   975
	m_hooks.push_back(pListener);
dvander@336
   976
}
dvander@336
   977
dvander@336
   978
void AdminCache::RemoveAdminListener(IAdminListener *pListener)
dvander@336
   979
{
dvander@336
   980
	m_hooks.remove(pListener);
dvander@336
   981
}
dvander@336
   982
dvander@404
   983
void AdminCache::RegisterAuthIdentType(const char *name)
dvander@404
   984
{
dvander@404
   985
	if (sm_trie_retrieve(m_pAuthTables, name, NULL))
dvander@404
   986
	{
dvander@404
   987
		return;
dvander@404
   988
	}
dvander@404
   989
dvander@404
   990
	Trie *pAuth = sm_trie_create();
dvander@404
   991
dvander@404
   992
	AuthMethod method;
dvander@404
   993
	method.name.assign(name);
dvander@404
   994
	method.table = pAuth;
dvander@404
   995
dvander@404
   996
	m_AuthMethods.push_back(method);
dvander@404
   997
dvander@404
   998
	sm_trie_insert(m_pAuthTables, name, pAuth);
dvander@404
   999
}
dvander@404
  1000
dvander@404
  1001
void AdminCache::InvalidateAdminCache(bool unlink_admins)
dvander@404
  1002
{
dvander@458
  1003
	m_InvalidatingAdmins = true;
dvander@520
  1004
	if (!m_destroying)
dvander@520
  1005
	{
dvander@520
  1006
		g_Players.ClearAllAdmins();
dvander@520
  1007
	}
dvander@404
  1008
	/* Wipe the identity cache first */
dvander@404
  1009
	List<AuthMethod>::iterator iter;
dvander@404
  1010
	for (iter=m_AuthMethods.begin();
dvander@404
  1011
		 iter!=m_AuthMethods.end();
dvander@404
  1012
		 iter++)
dvander@404
  1013
	{
dvander@404
  1014
		sm_trie_clear((*iter).table);
dvander@404
  1015
	}
dvander@404
  1016
	
dvander@405
  1017
	if (unlink_admins)
dvander@404
  1018
	{
dvander@405
  1019
		while (m_FirstUser != INVALID_ADMIN_ID)
dvander@405
  1020
		{
dvander@405
  1021
			InvalidateAdmin(m_FirstUser);
dvander@405
  1022
		}
dvander@405
  1023
	} else {
dvander@405
  1024
		m_FirstUser = -1;
dvander@405
  1025
		m_LastUser = -1;
dvander@405
  1026
		m_FreeUserList = -1;
dvander@404
  1027
	}
dvander@458
  1028
	m_InvalidatingAdmins = false;
dvander@404
  1029
}
dvander@404
  1030
dvander@438
  1031
void AdminCache::DumpAdminCache(AdminCachePart part, bool rebuild)
dvander@336
  1032
{
dvander@438
  1033
	List<IAdminListener *>::iterator iter;
dvander@438
  1034
	IAdminListener *pListener;
dvander@438
  1035
	cell_t result;
dvander@438
  1036
dvander@438
  1037
	if (part == AdminCache_Overrides)
dvander@336
  1038
	{
dvander@336
  1039
		DumpCommandOverrideCache(Override_Command);
dvander@336
  1040
		DumpCommandOverrideCache(Override_CommandGroup);
dvander@520
  1041
		if (rebuild && !m_destroying)
dvander@438
  1042
		{
dvander@438
  1043
			for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
dvander@438
  1044
			{
dvander@438
  1045
				pListener = (*iter);
dvander@438
  1046
				pListener->OnRebuildOverrideCache();
dvander@438
  1047
			}
dvander@438
  1048
			m_pCacheFwd->PushCell(part);
dvander@438
  1049
			m_pCacheFwd->Execute(&result);
dvander@438
  1050
		}
dvander@438
  1051
	} else if (part == AdminCache_Groups || part == AdminCache_Admins) {
dvander@438
  1052
		if (part == AdminCache_Groups)
dvander@438
  1053
		{
dvander@438
  1054
			InvalidateGroupCache();
dvander@520
  1055
			if (rebuild && !m_destroying)
dvander@438
  1056
			{
dvander@438
  1057
				for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
dvander@438
  1058
				{
dvander@438
  1059
					pListener = (*iter);
dvander@438
  1060
					pListener->OnRebuildGroupCache();
dvander@438
  1061
				}
dvander@438
  1062
				m_pCacheFwd->PushCell(part);
dvander@438
  1063
				m_pCacheFwd->Execute(&result);
dvander@438
  1064
			}
dvander@438
  1065
		}
dvander@404
  1066
		InvalidateAdminCache(true);
dvander@520
  1067
		if (rebuild && !m_destroying)
dvander@336
  1068
		{
dvander@438
  1069
			for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
dvander@438
  1070
			{
dvander@438
  1071
				pListener = (*iter);
dvander@438
  1072
				pListener->OnRebuildAdminCache((part == AdminCache_Groups));
dvander@438
  1073
			}
dvander@438
  1074
			m_pCacheFwd->PushCell(AdminCache_Admins);
dvander@438
  1075
			m_pCacheFwd->Execute(&result);
dvander@1165
  1076
			g_Players.RecheckAnyAdmins();
dvander@336
  1077
		}
dvander@336
  1078
	}
dvander@336
  1079
}
dvander@404
  1080
dvander@404
  1081
const char *AdminCache::GetAdminName(AdminId id)
dvander@404
  1082
{
dvander@404
  1083
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@404
  1084
	if (!pUser || pUser->magic != USR_MAGIC_SET)
dvander@404
  1085
	{
dvander@404
  1086
		return NULL;
dvander@404
  1087
	}
dvander@404
  1088
dvander@404
  1089
	return m_pStrings->GetString(pUser->nameidx);
dvander@404
  1090
}
dvander@404
  1091
dvander@405
  1092
bool AdminCache::GetMethodIndex(const char *name, unsigned int *_index)
dvander@405
  1093
{
dvander@405
  1094
	List<AuthMethod>::iterator iter;
dvander@405
  1095
	unsigned int index = 0;
dvander@405
  1096
	for (iter=m_AuthMethods.begin();
dvander@405
  1097
		 iter!=m_AuthMethods.end();
dvander@405
  1098
		 iter++,index++)
dvander@405
  1099
	{
dvander@405
  1100
		if ((*iter).name.compare(name) == 0)
dvander@405
  1101
		{
dvander@405
  1102
			*_index = index;
dvander@405
  1103
			return true;
dvander@405
  1104
		}
dvander@405
  1105
	}
dvander@405
  1106
dvander@405
  1107
	return false;
dvander@405
  1108
}
dvander@405
  1109
dvander@404
  1110
bool AdminCache::BindAdminIdentity(AdminId id, const char *auth, const char *ident)
dvander@404
  1111
{
dvander@404
  1112
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@404
  1113
	if (!pUser || pUser->magic != USR_MAGIC_SET)
dvander@404
  1114
	{
dvander@404
  1115
		return false;
dvander@404
  1116
	}
dvander@404
  1117
dvander@404
  1118
	Trie *pTable;
dvander@404
  1119
	if (!sm_trie_retrieve(m_pAuthTables, auth, (void **)&pTable))
dvander@404
  1120
	{
dvander@404
  1121
		return false;
dvander@404
  1122
	}
dvander@404
  1123
dvander@404
  1124
	if (sm_trie_retrieve(pTable, ident, NULL))
dvander@404
  1125
	{
dvander@404
  1126
		return false;
dvander@404
  1127
	}
dvander@404
  1128
dvander@405
  1129
	pUser->auth.identidx = m_pStrings->AddString(ident);
dvander@405
  1130
	GetMethodIndex(auth, &pUser->auth.index);
dvander@405
  1131
dvander@404
  1132
	return sm_trie_insert(pTable, ident, (void **)id);
dvander@404
  1133
}
dvander@404
  1134
dvander@404
  1135
AdminId AdminCache::FindAdminByIdentity(const char *auth, const char *identity)
dvander@404
  1136
{
dvander@404
  1137
	Trie *pTable;
dvander@404
  1138
	if (!sm_trie_retrieve(m_pAuthTables, auth, (void **)&pTable))
dvander@404
  1139
	{
dvander@404
  1140
		return INVALID_ADMIN_ID;
dvander@404
  1141
	}
dvander@404
  1142
dvander@404
  1143
	void *object;
dvander@404
  1144
	if (!sm_trie_retrieve(pTable, identity, &object))
dvander@404
  1145
	{
dvander@404
  1146
		return INVALID_ADMIN_ID;
dvander@404
  1147
	}
dvander@404
  1148
dvander@404
  1149
	return (AdminId)object;
dvander@404
  1150
}
dvander@404
  1151
dvander@404
  1152
void AdminCache::SetAdminFlag(AdminId id, AdminFlag flag, bool enabled)
dvander@404
  1153
{
dvander@404
  1154
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@404
  1155
	if (!pUser || pUser->magic != USR_MAGIC_SET)
dvander@404
  1156
	{
dvander@404
  1157
		return;
dvander@404
  1158
	}
dvander@404
  1159
dvander@433
  1160
	if (flag < Admin_Reservation
dvander@404
  1161
		|| flag >= AdminFlags_TOTAL)
dvander@404
  1162
	{
dvander@404
  1163
		return;
dvander@404
  1164
	}
dvander@436
  1165
	
dvander@436
  1166
	FlagBits bits = (1<<(FlagBits)flag);
dvander@404
  1167
dvander@436
  1168
	if (enabled)
dvander@436
  1169
	{
dvander@436
  1170
		pUser->flags |= bits;
dvander@436
  1171
		pUser->eflags |= bits;
dvander@436
  1172
	} else {
dvander@436
  1173
		pUser->flags &= ~bits;
dvander@436
  1174
		pUser->eflags &= ~bits;
dvander@436
  1175
	}
dvander@404
  1176
}
dvander@404
  1177
dvander@404
  1178
bool AdminCache::GetAdminFlag(AdminId id, AdminFlag flag, AccessMode mode)
dvander@404
  1179
{
dvander@404
  1180
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@404
  1181
	if (!pUser || pUser->magic != USR_MAGIC_SET)
dvander@404
  1182
	{
dvander@404
  1183
		return false;
dvander@404
  1184
	}
dvander@404
  1185
dvander@433
  1186
	if (flag < Admin_Reservation
dvander@404
  1187
		|| flag >= AdminFlags_TOTAL)
dvander@404
  1188
	{
dvander@404
  1189
		return false;
dvander@404
  1190
	}
dvander@404
  1191
dvander@433
  1192
	FlagBits bit = (1<<(FlagBits)flag);
dvander@433
  1193
dvander@404
  1194
	if (mode == Access_Real)
dvander@404
  1195
	{
dvander@433
  1196
		return ((pUser->flags & bit) == bit);
dvander@404
  1197
	} else if (mode == Access_Effective) {
dvander@907
  1198
		bool has_bit = ((pUser->eflags & bit) == bit);
dvander@907
  1199
		if (!has_bit && flag != Admin_Root && ((pUser->eflags & ADMFLAG_ROOT) == ADMFLAG_ROOT))
dvander@907
  1200
		{
dvander@907
  1201
			has_bit = true;
dvander@907
  1202
		}
dvander@907
  1203
		return has_bit;
dvander@404
  1204
	}
dvander@404
  1205
dvander@404
  1206
	return false;
dvander@404
  1207
}
dvander@404
  1208
dvander@433
  1209
FlagBits AdminCache::GetAdminFlags(AdminId id, AccessMode mode)
dvander@404
  1210
{
dvander@404
  1211
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@404
  1212
	if (!pUser || pUser->magic != USR_MAGIC_SET)
dvander@404
  1213
	{
dvander@404
  1214
		return 0;
dvander@404
  1215
	}
dvander@404
  1216
dvander@404
  1217
	if (mode == Access_Real)
dvander@404
  1218
	{
dvander@433
  1219
		return pUser->flags;
dvander@404
  1220
	} else if (mode == Access_Effective) {
dvander@433
  1221
		return pUser->eflags;
dvander@404
  1222
	}
dvander@404
  1223
dvander@433
  1224
	return 0;
dvander@404
  1225
}
dvander@404
  1226
dvander@458
  1227
void AdminCache::SetAdminFlags(AdminId id, AccessMode mode, FlagBits bits)
dvander@458
  1228
{
dvander@458
  1229
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@458
  1230
	if (!pUser || pUser->magic != USR_MAGIC_SET)
dvander@458
  1231
	{
dvander@458
  1232
		return;
dvander@458
  1233
	}
dvander@458
  1234
dvander@458
  1235
	if (mode == Access_Real)
dvander@458
  1236
	{
dvander@458
  1237
		pUser->flags = bits;
dvander@458
  1238
		pUser->eflags = bits;
dvander@458
  1239
	} else if (mode == Access_Effective) {
dvander@458
  1240
		pUser->eflags = bits;
dvander@458
  1241
	}
dvander@458
  1242
}
dvander@458
  1243
dvander@404
  1244
bool AdminCache::AdminInheritGroup(AdminId id, GroupId gid)
dvander@404
  1245
{
dvander@404
  1246
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@404
  1247
	if (!pUser || pUser->magic != USR_MAGIC_SET)
dvander@404
  1248
	{
dvander@404
  1249
		return false;
dvander@404
  1250
	}
dvander@404
  1251
dvander@404
  1252
	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(gid);
dvander@405
  1253
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@404
  1254
	{
dvander@404
  1255
		return false;
dvander@404
  1256
	}
dvander@404
  1257
dvander@433
  1258
	/* First check for duplicates */
dvander@433
  1259
	if (pUser->grp_count != 0)
dvander@433
  1260
	{
dvander@433
  1261
		int *temp_table = (int *)m_pMemory->GetAddress(pUser->grp_table);
dvander@433
  1262
		for (unsigned int i=0; i<pUser->grp_count; i++)
dvander@433
  1263
		{
dvander@433
  1264
			if (temp_table[i] == gid)
dvander@433
  1265
			{
dvander@433
  1266
				return false;
dvander@433
  1267
			}
dvander@433
  1268
		}
dvander@433
  1269
	}
dvander@433
  1270
dvander@404
  1271
	int *table;
dvander@404
  1272
	if (pUser->grp_count + 1 > pUser->grp_size)
dvander@404
  1273
	{
dvander@404
  1274
		int new_size = 0;
dvander@404
  1275
		int tblidx;
dvander@404
  1276
		
dvander@404
  1277
		if (pUser->grp_size == 0)
dvander@404
  1278
		{
dvander@404
  1279
			new_size = 2;
dvander@404
  1280
		} else {
dvander@404
  1281
			new_size = pUser->grp_size * 2;
dvander@404
  1282
		}
dvander@404
  1283
		
dvander@404
  1284
		/* Create and refresh pointers */
dvander@404
  1285
		tblidx = m_pMemory->CreateMem(new_size * sizeof(int), (void **)&table);
dvander@404
  1286
		pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@404
  1287
		pGroup = (AdminGroup *)m_pMemory->GetAddress(gid);
dvander@404
  1288
dvander@404
  1289
		/* Copy old data if necessary */
dvander@404
  1290
		if (pUser->grp_table != -1)
dvander@404
  1291
		{
dvander@404
  1292
			int *old_table = (int *)m_pMemory->GetAddress(pUser->grp_table);
dvander@404
  1293
			memcpy(table, old_table, sizeof(int) * pUser->grp_count);
dvander@404
  1294
		}
dvander@404
  1295
		pUser->grp_table = tblidx;
dvander@404
  1296
		pUser->grp_size = new_size;
dvander@404
  1297
	} else {
dvander@404
  1298
		table = (int *)m_pMemory->GetAddress(pUser->grp_table);
dvander@404
  1299
	}
dvander@404
  1300
dvander@404
  1301
	table[pUser->grp_count] = gid;
dvander@404
  1302
	pUser->grp_count++;
dvander@404
  1303
dvander@434
  1304
	/* Compute new effective permissions */
dvander@433
  1305
	pUser->eflags |= pGroup->addflags;
dvander@404
  1306
dvander@434
  1307
	if (pGroup->immune_default)
dvander@434
  1308
	{
dvander@434
  1309
		pUser->immune_default = true;
dvander@434
  1310
	}
dvander@434
  1311
	if (pGroup->immune_global)
dvander@434
  1312
	{
dvander@434
  1313
		pUser->immune_global = true;
dvander@434
  1314
	}
dvander@434
  1315
dvander@404
  1316
	return true;
dvander@404
  1317
}
dvander@404
  1318
dvander@458
  1319
bool AdminCache::IsValidAdmin(AdminId id)
dvander@458
  1320
{
dvander@458
  1321
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@458
  1322
	return (pUser != NULL && pUser->magic == USR_MAGIC_SET);
dvander@458
  1323
}
dvander@458
  1324
dvander@404
  1325
unsigned int AdminCache::GetAdminGroupCount(AdminId id)
dvander@404
  1326
{
dvander@404
  1327
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@404
  1328
	if (!pUser || pUser->magic != USR_MAGIC_SET)
dvander@404
  1329
	{
dvander@404
  1330
		return 0;
dvander@404
  1331
	}
dvander@404
  1332
dvander@404
  1333
	return pUser->grp_count;
dvander@404
  1334
}
dvander@404
  1335
dvander@404
  1336
GroupId AdminCache::GetAdminGroup(AdminId id, unsigned int index, const char **name)
dvander@404
  1337
{
dvander@404
  1338
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@404
  1339
	if (!pUser || pUser->magic != USR_MAGIC_SET || index >= pUser->grp_count)
dvander@404
  1340
	{
dvander@404
  1341
		return INVALID_GROUP_ID;
dvander@404
  1342
	}
dvander@404
  1343
dvander@404
  1344
	int *table = (int *)m_pMemory->GetAddress(pUser->grp_table);
dvander@404
  1345
dvander@404
  1346
	return table[index];
dvander@404
  1347
}
dvander@404
  1348
dvander@404
  1349
const char *AdminCache::GetAdminPassword(AdminId id)
dvander@404
  1350
{
dvander@404
  1351
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@404
  1352
	if (!pUser || pUser->magic != USR_MAGIC_SET)
dvander@404
  1353
	{
dvander@404
  1354
		return NULL;
dvander@404
  1355
	}
dvander@404
  1356
dvander@404
  1357
	return m_pStrings->GetString(pUser->password);
dvander@404
  1358
}
dvander@404
  1359
dvander@404
  1360
void AdminCache::SetAdminPassword(AdminId id, const char *password)
dvander@404
  1361
{	
dvander@404
  1362
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@404
  1363
	if (!pUser || pUser->magic != USR_MAGIC_SET)
dvander@404
  1364
	{
dvander@404
  1365
		return;
dvander@404
  1366
	}
dvander@404
  1367
dvander@404
  1368
	pUser->password = m_pStrings->AddString(password);
dvander@404
  1369
}
dvander@404
  1370
dvander@433
  1371
unsigned int AdminCache::FlagBitsToBitArray(FlagBits bits, bool array[], unsigned int maxSize)
dvander@433
  1372
{
dvander@433
  1373
	unsigned int i;
dvander@433
  1374
	for (i=0; i<maxSize && i<AdminFlags_TOTAL; i++)
dvander@433
  1375
	{
dvander@464
  1376
		array[i] = ((bits & (1<<i)) == (unsigned)(1<<i));
dvander@433
  1377
	}
dvander@433
  1378
dvander@433
  1379
	return i;
dvander@433
  1380
}
dvander@433
  1381
dvander@433
  1382
FlagBits AdminCache::FlagBitArrayToBits(const bool array[], unsigned int maxSize)
dvander@433
  1383
{
dvander@433
  1384
	FlagBits bits = 0;
dvander@433
  1385
	for (unsigned int i=0; i<maxSize && i<AdminFlags_TOTAL; i++)
dvander@433
  1386
	{
dvander@433
  1387
		if (array[i])
dvander@433
  1388
		{
dvander@433
  1389
			bits |= (1<<i);
dvander@433
  1390
		}
dvander@433
  1391
	}
dvander@433
  1392
dvander@433
  1393
	return bits;
dvander@433
  1394
}
dvander@433
  1395
dvander@433
  1396
FlagBits AdminCache::FlagArrayToBits(const AdminFlag array[], unsigned int numFlags)
dvander@433
  1397
{
dvander@433
  1398
	FlagBits bits = 0;
dvander@433
  1399
	for (unsigned int i=0; i<numFlags && i<AdminFlags_TOTAL; i++)
dvander@433
  1400
	{
dvander@433
  1401
		bits |= (1 << (FlagBits)array[i]);
dvander@433
  1402
	}
dvander@433
  1403
dvander@433
  1404
	return bits;
dvander@433
  1405
}
dvander@433
  1406
dvander@433
  1407
unsigned int AdminCache::FlagBitsToArray(FlagBits bits, AdminFlag array[], unsigned int maxSize)
dvander@433
  1408
{
dvander@433
  1409
	unsigned int i, num=0;
dvander@1050
  1410
	for (i=0; num<maxSize && i<AdminFlags_TOTAL; i++)
dvander@433
  1411
	{
dvander@464
  1412
		if ((bits & (1<<i)) == (unsigned)(1<<i))
dvander@433
  1413
		{
dvander@433
  1414
			array[num++] = (AdminFlag)i;
dvander@433
  1415
		}
dvander@433
  1416
	}
dvander@433
  1417
dvander@433
  1418
	return num;
dvander@433
  1419
}
dvander@434
  1420
dvander@434
  1421
bool AdminCache::CheckAdminFlags(AdminId id, FlagBits bits)
dvander@434
  1422
{
dvander@434
  1423
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@434
  1424
	if (!pUser || pUser->magic != USR_MAGIC_SET)
dvander@434
  1425
	{
dvander@434
  1426
		return false;
dvander@434
  1427
	}
dvander@434
  1428
dvander@434
  1429
	return ((pUser->eflags & bits) == bits);
dvander@434
  1430
}
dvander@434
  1431
dvander@434
  1432
bool AdminCache::CanAdminTarget(AdminId id, AdminId target)
dvander@434
  1433
{
dvander@434
  1434
	/** 
dvander@434
  1435
	 * Zeroth, if the targeting AdminId is INVALID_ADMIN_ID, targeting fails.
ds@729
  1436
	 * First, if the targeted AdminId is INVALID_ADMIN_ID, targeting succeeds.
dvander@434
  1437
	 */
dvander@434
  1438
dvander@434
  1439
	if (id == INVALID_ADMIN_ID)
dvander@434
  1440
	{
dvander@434
  1441
		return false;
dvander@434
  1442
	}
dvander@434
  1443
dvander@434
  1444
	if (target == INVALID_ADMIN_ID)
dvander@434
  1445
	{
dvander@434
  1446
		return true;
dvander@434
  1447
	}
dvander@434
  1448
dvander@434
  1449
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@434
  1450
	if (!pUser || pUser->magic != USR_MAGIC_SET)
dvander@434
  1451
	{
dvander@434
  1452
		return false;
dvander@434
  1453
	}
dvander@434
  1454
dvander@434
  1455
	AdminUser *pTarget = (AdminUser *)m_pMemory->GetAddress(target);
dvander@434
  1456
	if (!pTarget || pTarget->magic != USR_MAGIC_SET)
dvander@434
  1457
	{
dvander@434
  1458
		return false;
dvander@434
  1459
	}
dvander@434
  1460
dvander@434
  1461
	/** 
ds@729
  1462
	 * Second, if the targeting admin is root, targeting succeeds.
dvander@434
  1463
	 */
dvander@434
  1464
	if (pUser->eflags & ADMFLAG_ROOT)
dvander@434
  1465
	{
dvander@434
  1466
		return true;
dvander@434
  1467
	}
dvander@434
  1468
ds@729
  1469
	/** Fourth, if the targeted admin has global immunity, targeting fails. */
dvander@434
  1470
	if (pTarget->immune_global)
dvander@434
  1471
	{
dvander@434
  1472
		return false;
dvander@434
  1473
	}
dvander@434
  1474
dvander@434
  1475
	/** 
ds@729
  1476
	 * Fifth, if the targeted admin has default immunity 
dvander@434
  1477
	 *  and the admin belongs to no groups, targeting fails.
dvander@434
  1478
	 */
dvander@434
  1479
	if (pTarget->immune_default && pUser->grp_count < 1)
dvander@434
  1480
	{
dvander@434
  1481
		return false;
dvander@434
  1482
	}
dvander@434
  1483
dvander@434
  1484
	/** 
ds@729
  1485
	 * Sixth, if the targeted admin has specific immunity from the
dvander@434
  1486
	 *  targeting admin via group immunities, targeting fails.
dvander@434
  1487
	 */
dvander@434
  1488
	//:TODO: speed this up... maybe with trie hacks.
dvander@434
  1489
	//idea is to insert %d.%d in the trie after computing this and use it as a cache lookup.
dvander@434
  1490
	//problem is the trie cannot delete prefixes, so we'd have a problem with invalidations.
dvander@434
  1491
	if (pTarget->grp_count > 0 && pUser->grp_count > 0)
dvander@434
  1492
	{
dvander@434
  1493
		int *grp_table = (int *)m_pMemory->GetAddress(pTarget->grp_table);
dvander@434
  1494
		int *src_table = (int *)m_pMemory->GetAddress(pUser->grp_table);
dvander@434
  1495
		GroupId id, other;
dvander@434
  1496
		unsigned int num;
dvander@434
  1497
		for (unsigned int i=0; i<pTarget->grp_count; i++)
dvander@434
  1498
		{
dvander@434
  1499
			id = grp_table[i];
dvander@434
  1500
			num = GetGroupImmunityCount(id);
dvander@434
  1501
			for (unsigned int j=0; j<num; i++)
dvander@434
  1502
			{
dvander@434
  1503
				other = GetGroupImmunity(id, j);
dvander@434
  1504
				for (unsigned int k=0; k<pUser->grp_count; k++)
dvander@434
  1505
				{
dvander@434
  1506
					if (other == src_table[k])
dvander@434
  1507
					{
dvander@434
  1508
						return false;
dvander@434
  1509
					}
dvander@434
  1510
				}
dvander@434
  1511
			}
dvander@434
  1512
		}
dvander@434
  1513
	}
dvander@434
  1514
	
dvander@434
  1515
	return true;
dvander@434
  1516
}
dvander@1298
  1517
dvander@1298
  1518
bool AdminCache::FindFlag(char c, AdminFlag *pAdmFlag)
dvander@1298
  1519
{
dvander@1298
  1520
	if (c < 'a' || c > 'z')
dvander@1298
  1521
	{
dvander@1298
  1522
		return false;
dvander@1298
  1523
	}
dvander@1298
  1524
dvander@1305
  1525
	if (pAdmFlag)
dvander@1298
  1526
	{
dvander@1298
  1527
		*pAdmFlag = g_FlagLetters[(unsigned)c - (unsigned)'a'];
dvander@1298
  1528
	}
dvander@1298
  1529
dvander@1298
  1530
	return true;
dvander@1298
  1531
}
dvander@1298
  1532
dvander@1298
  1533
FlagBits AdminCache::ReadFlagString(const char *flags, const char **end)
dvander@1298
  1534
{
dvander@1298
  1535
	FlagBits bits = 0;
dvander@1298
  1536
dvander@1298
  1537
	while (flags && (*flags != '\0'))
dvander@1298
  1538
	{
dvander@1298
  1539
		AdminFlag flag;
dvander@1298
  1540
		if (!FindFlag(*flags, &flag))
dvander@1298
  1541
		{
dvander@1298
  1542
			break;
dvander@1298
  1543
		}
dvander@1298
  1544
		bits |= FlagArrayToBits(&flag, 1);
dvander@1298
  1545
		flags++;
dvander@1298
  1546
	}
dvander@1298
  1547
dvander@1298
  1548
	if (end)
dvander@1298
  1549
	{
dvander@1298
  1550
		*end = flags;
dvander@1298
  1551
	}
dvander@1298
  1552
dvander@1298
  1553
	return bits;
dvander@1298
  1554
}