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