core/AdminCache.cpp
author Scott Ehlert <ds@alliedmods.net>
Wed Aug 15 06:19:30 2007 +0000 (2007-08-15)
changeset 1330 ab94316bb52b
parent 1305 72711a64a086
child 1349 0d84046ec139
permissions -rw-r--r--
Updated license headers on virtually all files with extremely minor changes in the name of some sort of strange consistency.
All plugin and include file headers also have been changed to say about GPL3 instead of GPL2.

(This day shall henceforth be known as the Eighty Column Massacre of '07)
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@404
   448
dvander@404
   449
	if (m_FirstUser == INVALID_ADMIN_ID)
dvander@404
   450
	{
dvander@404
   451
		m_FirstUser = id;
dvander@404
   452
		m_LastUser = id;
dvander@404
   453
	} else {
dvander@404
   454
		AdminUser *pPrev = (AdminUser *)m_pMemory->GetAddress(m_LastUser);
dvander@404
   455
		pPrev->next_user = id;
dvander@404
   456
		pUser->prev_user = m_LastUser;
dvander@404
   457
		m_LastUser = id;
dvander@404
   458
	}
dvander@404
   459
dvander@404
   460
	if (name && name[0] != '\0')
dvander@404
   461
	{
dvander@404
   462
		pUser->nameidx = m_pStrings->AddString(name);
dvander@404
   463
	}
dvander@404
   464
dvander@404
   465
	return id;
dvander@404
   466
}
dvander@404
   467
dvander@335
   468
GroupId AdminCache::AddGroup(const char *group_name)
dvander@335
   469
{
dvander@335
   470
	if (sm_trie_retrieve(m_pGroups, group_name, NULL))
dvander@335
   471
	{
dvander@335
   472
		return INVALID_GROUP_ID;
dvander@335
   473
	}
dvander@335
   474
dvander@335
   475
	GroupId id;
dvander@335
   476
	AdminGroup *pGroup;
dvander@335
   477
	if (m_FreeGroupList != INVALID_GROUP_ID)
dvander@335
   478
	{
dvander@335
   479
		pGroup = (AdminGroup *)m_pMemory->GetAddress(m_FreeGroupList);
dvander@335
   480
		assert(pGroup->magic == GRP_MAGIC_UNSET);
dvander@335
   481
		id = m_FreeGroupList;
dvander@335
   482
		m_FreeGroupList = pGroup->next_grp;
dvander@335
   483
	} else {
dvander@335
   484
		id = m_pMemory->CreateMem(sizeof(AdminGroup), (void **)&pGroup);
dvander@335
   485
	}
dvander@335
   486
dvander@335
   487
	pGroup->immune_default = false;
dvander@335
   488
	pGroup->immune_global = false;
dvander@335
   489
	pGroup->immune_table = -1;
dvander@335
   490
	pGroup->magic = GRP_MAGIC_SET;
dvander@335
   491
	pGroup->next_grp = INVALID_GROUP_ID;
dvander@335
   492
	pGroup->pCmdGrpTable = NULL;
dvander@335
   493
	pGroup->pCmdTable = NULL;
dvander@433
   494
	pGroup->addflags = 0;
dvander@335
   495
dvander@335
   496
	if (m_FirstGroup == INVALID_GROUP_ID)
dvander@335
   497
	{
dvander@335
   498
		m_FirstGroup = id;
dvander@335
   499
		m_LastGroup = id;
dvander@335
   500
		pGroup->prev_grp = INVALID_GROUP_ID;
dvander@335
   501
	} else {
dvander@335
   502
		AdminGroup *pPrev = (AdminGroup *)m_pMemory->GetAddress(m_LastGroup);
dvander@335
   503
		assert(pPrev->magic == GRP_MAGIC_SET);
dvander@335
   504
		pPrev->next_grp = id;
dvander@335
   505
		pGroup->prev_grp = m_LastGroup;
dvander@335
   506
		m_LastGroup = id;
dvander@335
   507
	}
dvander@335
   508
dvander@404
   509
	pGroup->nameidx = m_pStrings->AddString(group_name);
dvander@404
   510
dvander@335
   511
	sm_trie_insert(m_pGroups, group_name, (void *)id);
dvander@335
   512
dvander@335
   513
	return id;
dvander@335
   514
}
dvander@335
   515
dvander@335
   516
GroupId AdminCache::FindGroupByName(const char *group_name)
dvander@335
   517
{
dvander@335
   518
	void *object;
dvander@335
   519
dvander@335
   520
	if (!sm_trie_retrieve(m_pGroups, group_name, &object))
dvander@335
   521
	{
dvander@335
   522
		return INVALID_GROUP_ID;
dvander@335
   523
	}
dvander@335
   524
dvander@335
   525
	GroupId id = (GroupId)object;
dvander@335
   526
	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
dvander@335
   527
dvander@335
   528
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@335
   529
	{
dvander@335
   530
		return INVALID_GROUP_ID;
dvander@335
   531
	}
dvander@335
   532
dvander@335
   533
	return id;
dvander@335
   534
}
dvander@335
   535
dvander@335
   536
void AdminCache::SetGroupAddFlag(GroupId id, AdminFlag flag, bool enabled)
dvander@335
   537
{
dvander@335
   538
	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
dvander@335
   539
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@335
   540
	{
dvander@335
   541
		return;
dvander@335
   542
	}
dvander@335
   543
dvander@433
   544
	if (flag < Admin_Reservation || flag >= AdminFlags_TOTAL)
dvander@335
   545
	{
dvander@335
   546
		return;
dvander@335
   547
	}
dvander@335
   548
dvander@436
   549
	FlagBits bits = (1<<(FlagBits)flag);
dvander@436
   550
dvander@436
   551
	if (enabled)
dvander@436
   552
	{
dvander@436
   553
		pGroup->addflags |= bits;
dvander@436
   554
	} else {
dvander@436
   555
		pGroup->addflags &= ~bits;
dvander@436
   556
	}
dvander@335
   557
}
dvander@335
   558
dvander@335
   559
bool AdminCache::GetGroupAddFlag(GroupId id, AdminFlag flag)
dvander@335
   560
{
dvander@335
   561
	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
dvander@335
   562
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@335
   563
	{
dvander@335
   564
		return false;
dvander@335
   565
	}
dvander@335
   566
dvander@433
   567
	if (flag < Admin_Reservation || flag >= AdminFlags_TOTAL)
dvander@335
   568
	{
dvander@335
   569
		return false;
dvander@335
   570
	}
dvander@335
   571
dvander@433
   572
	FlagBits bit = 1<<(FlagBits)flag;
dvander@433
   573
	return ((pGroup->addflags & bit) == bit);
dvander@335
   574
}
dvander@335
   575
dvander@433
   576
FlagBits AdminCache::GetGroupAddFlags(GroupId id)
dvander@335
   577
{
dvander@335
   578
	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
dvander@335
   579
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@335
   580
	{
dvander@335
   581
		return 0;
dvander@335
   582
	}
dvander@335
   583
dvander@433
   584
	return pGroup->addflags;
dvander@335
   585
}
dvander@335
   586
dvander@335
   587
void AdminCache::SetGroupGenericImmunity(GroupId id, ImmunityType type, bool enabled)
dvander@335
   588
{
dvander@335
   589
	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
dvander@335
   590
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@335
   591
	{
dvander@335
   592
		return;
dvander@335
   593
	}
dvander@335
   594
dvander@335
   595
	if (type == Immunity_Default)
dvander@335
   596
	{
dvander@335
   597
		pGroup->immune_default = enabled;
dvander@335
   598
	} else if (type == Immunity_Global) {
dvander@335
   599
		pGroup->immune_global = enabled;
dvander@335
   600
	} 
dvander@335
   601
}
dvander@335
   602
dvander@335
   603
bool AdminCache::GetGroupGenericImmunity(GroupId id, ImmunityType type)
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 false;
dvander@335
   609
	}
dvander@335
   610
dvander@335
   611
	if (type == Immunity_Default)
dvander@335
   612
	{
dvander@335
   613
		return pGroup->immune_default;
dvander@335
   614
	} else if (type == Immunity_Global) {
dvander@335
   615
		return pGroup->immune_global;
dvander@335
   616
	}
dvander@335
   617
dvander@335
   618
	return false;
dvander@335
   619
}
dvander@335
   620
dvander@335
   621
void AdminCache::AddGroupImmunity(GroupId id, GroupId other_id)
dvander@335
   622
{
dvander@335
   623
	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
dvander@335
   624
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@335
   625
	{
dvander@335
   626
		return;
dvander@335
   627
	}
dvander@335
   628
dvander@335
   629
	AdminGroup *pOther = (AdminGroup *)m_pMemory->GetAddress(id);
dvander@335
   630
	if (!pOther || pOther->magic != GRP_MAGIC_SET)
dvander@335
   631
	{
dvander@335
   632
		return;
dvander@335
   633
	}
dvander@335
   634
dvander@335
   635
	/* We always need to resize the immunity table */
dvander@335
   636
	int *table, tblidx;
dvander@335
   637
	if (pOther->immune_table == -1)
dvander@335
   638
	{
dvander@335
   639
		tblidx = m_pMemory->CreateMem(sizeof(int) * 2, (void **)&table);
dvander@335
   640
		table[0] = 0;
dvander@335
   641
	} else {
dvander@335
   642
		int *old_table = (int *)m_pMemory->GetAddress(pOther->immune_table);
dvander@433
   643
		/* Break out if this group is already in the list */
dvander@433
   644
		for (int i=0; i<old_table[0]; i++)
dvander@433
   645
		{
dvander@433
   646
			if (old_table[1+i] == other_id)
dvander@433
   647
			{
dvander@433
   648
				return;
dvander@433
   649
			}
dvander@433
   650
		}
dvander@335
   651
		tblidx = m_pMemory->CreateMem(sizeof(int) * (old_table[0] + 2), (void **)&table);
dvander@433
   652
		/* Get the old address again in case of resize */
dvander@335
   653
		old_table = (int *)m_pMemory->GetAddress(pOther->immune_table);
dvander@335
   654
		table[0] = old_table[0];
dvander@335
   655
		for (unsigned int i=1; i<=(unsigned int)old_table[0]; i++)
dvander@335
   656
		{
dvander@335
   657
			table[i] = old_table[i];
dvander@335
   658
		}
dvander@335
   659
	}
dvander@335
   660
dvander@335
   661
	/* Assign */
dvander@335
   662
	pOther->immune_table = tblidx;
dvander@335
   663
dvander@335
   664
	/* Add to the array */
dvander@335
   665
	table[0]++;
dvander@335
   666
	table[table[0]] = other_id;
dvander@335
   667
}
dvander@335
   668
dvander@335
   669
unsigned int AdminCache::GetGroupImmunityCount(GroupId id)
dvander@335
   670
{
dvander@335
   671
	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
dvander@335
   672
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@335
   673
	{
dvander@335
   674
		return 0;
dvander@335
   675
	}
dvander@335
   676
dvander@335
   677
	if (pGroup->immune_table == -1)
dvander@335
   678
	{
dvander@335
   679
		return 0;
dvander@335
   680
	}
dvander@335
   681
dvander@335
   682
	int *table = (int *)m_pMemory->GetAddress(pGroup->immune_table);
dvander@335
   683
dvander@335
   684
	return table[0];
dvander@335
   685
}
dvander@335
   686
dvander@335
   687
GroupId AdminCache::GetGroupImmunity(GroupId id, unsigned int number)
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 INVALID_GROUP_ID;
dvander@335
   693
	}
dvander@335
   694
dvander@335
   695
	if (pGroup->immune_table == -1)
dvander@335
   696
	{
dvander@335
   697
		return INVALID_GROUP_ID;
dvander@335
   698
	}
dvander@335
   699
dvander@335
   700
	int *table = (int *)m_pMemory->GetAddress(pGroup->immune_table);
dvander@335
   701
	if (number >= (unsigned int)table[0])
dvander@335
   702
	{
dvander@335
   703
		return INVALID_GROUP_ID;
dvander@335
   704
	}
dvander@335
   705
dvander@335
   706
	return table[1 + number];
dvander@335
   707
}
dvander@335
   708
dvander@335
   709
void AdminCache::AddGroupCommandOverride(GroupId id, const char *name, OverrideType type, OverrideRule rule)
dvander@335
   710
{
dvander@335
   711
	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
dvander@335
   712
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@335
   713
	{
dvander@335
   714
		return;
dvander@335
   715
	}
dvander@335
   716
dvander@335
   717
	Trie *pTrie = NULL;
dvander@335
   718
	if (type == Override_Command)
dvander@335
   719
	{
dvander@335
   720
		if (pGroup->pCmdTable == NULL)
dvander@335
   721
		{
dvander@335
   722
			pGroup->pCmdTable = sm_trie_create();
dvander@335
   723
		}
dvander@335
   724
		pTrie = pGroup->pCmdTable;
dvander@335
   725
	} else if (type == Override_CommandGroup) {
dvander@335
   726
		if (pGroup->pCmdGrpTable == NULL)
dvander@335
   727
		{
dvander@335
   728
			pGroup->pCmdGrpTable = sm_trie_create();
dvander@335
   729
		}
dvander@335
   730
		pTrie = pGroup->pCmdGrpTable;
dvander@335
   731
	} else {
dvander@335
   732
		return;
dvander@335
   733
	}
dvander@335
   734
dvander@335
   735
	sm_trie_insert(pTrie, name, (void *)(int)rule);
dvander@335
   736
}
dvander@335
   737
dvander@335
   738
bool AdminCache::GetGroupCommandOverride(GroupId id, const char *name, OverrideType type, OverrideRule *pRule)
dvander@335
   739
{
dvander@335
   740
	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
dvander@335
   741
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@335
   742
	{
dvander@335
   743
		return false;
dvander@335
   744
	}
dvander@335
   745
dvander@335
   746
	Trie *pTrie = NULL;
dvander@335
   747
	if (type == Override_Command)
dvander@335
   748
	{
dvander@335
   749
		if (pGroup->pCmdTable == NULL)
dvander@335
   750
		{
dvander@335
   751
			return false;
dvander@335
   752
		}
dvander@335
   753
		pTrie = pGroup->pCmdTable;
dvander@335
   754
	} else if (type == Override_CommandGroup) {
dvander@335
   755
		if (pGroup->pCmdGrpTable == NULL)
dvander@335
   756
		{
dvander@335
   757
			return false;
dvander@335
   758
		}
dvander@335
   759
		pTrie = pGroup->pCmdGrpTable;
dvander@335
   760
	} else {
dvander@335
   761
		return false;
dvander@335
   762
	}
dvander@335
   763
dvander@335
   764
	void *object;
dvander@335
   765
	if (!sm_trie_retrieve(pTrie, name, &object))
dvander@335
   766
	{
dvander@335
   767
		return false;
dvander@335
   768
	}
dvander@335
   769
dvander@335
   770
	if (pRule)
dvander@335
   771
	{
dvander@335
   772
		*pRule = (OverrideRule)(int)object;
dvander@335
   773
	}
dvander@335
   774
	
dvander@335
   775
	return true;
dvander@335
   776
}
dvander@335
   777
dvander@404
   778
Trie *AdminCache::GetMethodByIndex(unsigned int index)
dvander@404
   779
{
dvander@404
   780
	List<AuthMethod>::iterator iter;
dvander@404
   781
	for (iter=m_AuthMethods.begin();
dvander@404
   782
		 iter!=m_AuthMethods.end();
dvander@404
   783
		 iter++)
dvander@404
   784
	{
dvander@404
   785
		if (index-- == 0)
dvander@404
   786
		{
dvander@404
   787
			return (*iter).table;
dvander@404
   788
		}
dvander@404
   789
	}
dvander@404
   790
dvander@404
   791
	return NULL;
dvander@404
   792
}
dvander@404
   793
dvander@404
   794
bool AdminCache::InvalidateAdmin(AdminId id)
dvander@404
   795
{
dvander@404
   796
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@404
   797
	AdminUser *pOther;
dvander@404
   798
	if (!pUser || pUser->magic != USR_MAGIC_SET)
dvander@404
   799
	{
dvander@404
   800
		return false;
dvander@404
   801
	}
dvander@404
   802
dvander@520
   803
	if (!m_InvalidatingAdmins && !m_destroying)
dvander@458
   804
	{
dvander@458
   805
		g_Players.ClearAdminId(id);
dvander@458
   806
	}
dvander@458
   807
dvander@404
   808
	/* Unlink from the dbl link list */
dvander@404
   809
	if (id == m_FirstUser && id == m_LastUser)
dvander@404
   810
	{
dvander@404
   811
		m_FirstUser = INVALID_ADMIN_ID;
dvander@404
   812
		m_LastUser = INVALID_ADMIN_ID;
dvander@404
   813
	} else if (id == m_FirstUser) {
dvander@404
   814
		m_FirstUser = pUser->next_user;
dvander@404
   815
		pOther = (AdminUser *)m_pMemory->GetAddress(m_FirstUser);
dvander@404
   816
		pOther->prev_user = INVALID_ADMIN_ID;
dvander@404
   817
	} else if (id == m_LastUser) {
dvander@404
   818
		m_LastUser = pUser->prev_user;
dvander@404
   819
		pOther = (AdminUser *)m_pMemory->GetAddress(m_LastUser);
dvander@404
   820
		pOther->next_user = INVALID_ADMIN_ID;
dvander@404
   821
	} else {
dvander@404
   822
		pOther = (AdminUser *)m_pMemory->GetAddress(pUser->prev_user);
dvander@404
   823
		pOther->next_user = pUser->next_user;
dvander@404
   824
		pOther = (AdminUser *)m_pMemory->GetAddress(pUser->next_user);
dvander@404
   825
		pOther->prev_user = pUser->prev_user;
dvander@404
   826
	}
dvander@404
   827
dvander@404
   828
	/* Unlink from auth tables */
dvander@405
   829
	if (pUser->auth.identidx != -1)
dvander@404
   830
	{
dvander@405
   831
		Trie *pTrie = GetMethodByIndex(pUser->auth.index);
dvander@405
   832
		if (pTrie)
dvander@404
   833
		{
dvander@405
   834
			sm_trie_delete(pTrie, m_pStrings->GetString(pUser->auth.identidx));
dvander@404
   835
		}
dvander@404
   836
	}
dvander@404
   837
dvander@404
   838
	/* Clear table counts */
dvander@404
   839
	pUser->grp_count = 0;
dvander@405
   840
	
dvander@404
   841
	/* Link into free list */
dvander@404
   842
	pUser->magic = USR_MAGIC_UNSET;
dvander@404
   843
	pUser->next_user = m_FreeUserList;
dvander@404
   844
	m_FreeUserList = id;
dvander@404
   845
dvander@404
   846
	return true;
dvander@404
   847
}
dvander@404
   848
dvander@404
   849
dvander@335
   850
void AdminCache::InvalidateGroup(GroupId id)
dvander@335
   851
{
dvander@335
   852
	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
dvander@335
   853
	AdminGroup *pOther;
dvander@335
   854
dvander@335
   855
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@335
   856
	{
dvander@335
   857
		return;
dvander@335
   858
	}
dvander@335
   859
dvander@335
   860
	const char *str = m_pStrings->GetString(pGroup->nameidx);
dvander@335
   861
	sm_trie_delete(m_pGroups, str);
dvander@335
   862
dvander@335
   863
	/* Unlink from the live dbllink list */
dvander@335
   864
	if (id == m_FirstGroup && id == m_LastGroup)
dvander@335
   865
	{
dvander@335
   866
		m_LastGroup = INVALID_GROUP_ID;
dvander@335
   867
		m_FirstGroup = INVALID_GROUP_ID;
dvander@335
   868
	} else if (id == m_FirstGroup) {
dvander@335
   869
		m_FirstGroup = pGroup->next_grp;
dvander@335
   870
		pOther = (AdminGroup *)m_pMemory->GetAddress(m_FirstGroup);
dvander@335
   871
		pOther->prev_grp = INVALID_GROUP_ID;
dvander@335
   872
	} else if (id == m_LastGroup) {
dvander@335
   873
		m_LastGroup = pGroup->prev_grp;
dvander@335
   874
		pOther = (AdminGroup *)m_pMemory->GetAddress(m_LastGroup);
dvander@335
   875
		pOther->next_grp = INVALID_GROUP_ID;
dvander@335
   876
	} else {
dvander@335
   877
		pOther = (AdminGroup *)m_pMemory->GetAddress(pGroup->prev_grp);
dvander@335
   878
		pOther->next_grp = pGroup->next_grp;
dvander@335
   879
		pOther = (AdminGroup *)m_pMemory->GetAddress(pGroup->next_grp);
dvander@335
   880
		pOther->prev_grp = pGroup->prev_grp;
dvander@335
   881
	}
dvander@335
   882
dvander@335
   883
	/* Free any used memory to be safe */
dvander@335
   884
	if (pGroup->pCmdGrpTable)
dvander@335
   885
	{
dvander@335
   886
		sm_trie_destroy(pGroup->pCmdGrpTable);
dvander@335
   887
		pGroup->pCmdGrpTable = NULL;
dvander@335
   888
	}
dvander@335
   889
	if (pGroup->pCmdTable)
dvander@335
   890
	{
dvander@335
   891
		sm_trie_destroy(pGroup->pCmdTable);
dvander@335
   892
		pGroup->pCmdTable = NULL;
dvander@335
   893
	}
dvander@335
   894
dvander@335
   895
	/* Link into the free list */
dvander@335
   896
	pGroup->magic = GRP_MAGIC_UNSET;
dvander@335
   897
	pGroup->next_grp = m_FreeGroupList;
dvander@335
   898
	m_FreeGroupList = id;
dvander@335
   899
dvander@404
   900
	int idx = m_FirstUser;
dvander@404
   901
	AdminUser *pUser;
dvander@404
   902
	int *table;
dvander@404
   903
	while (idx != INVALID_ADMIN_ID)
dvander@404
   904
	{
dvander@404
   905
		pUser = (AdminUser *)m_pMemory->GetAddress(idx);
dvander@404
   906
		if (pUser->grp_count > 0)
dvander@404
   907
		{
dvander@404
   908
			table = (int *)m_pMemory->GetAddress(pUser->grp_table);
dvander@404
   909
			for (unsigned int i=0; i<pUser->grp_count; i++)
dvander@404
   910
			{
dvander@404
   911
				if (table[i] == id)
dvander@404
   912
				{
dvander@404
   913
					/* We have to remove this entry */
dvander@404
   914
					for (unsigned int j=i+1; j<pUser->grp_count; j++)
dvander@404
   915
					{
dvander@404
   916
						/* Move everything down by one */
dvander@404
   917
						table[j-1] = table[j];
dvander@404
   918
					}
dvander@404
   919
					/* Decrease count */
dvander@404
   920
					pUser->grp_count--;
dvander@404
   921
					/* Recalculate effective flags */
dvander@433
   922
					pUser->eflags = pUser->flags;
dvander@404
   923
					for (unsigned int j=0; j<pUser->grp_count; j++)
dvander@404
   924
					{
dvander@404
   925
						pOther = (AdminGroup *)m_pMemory->GetAddress(table[j]);
dvander@433
   926
						pUser->eflags |= pOther->addflags;
dvander@404
   927
					}
dvander@404
   928
					/* Break now, duplicates aren't allowed */
dvander@404
   929
					break;
dvander@404
   930
				}
dvander@404
   931
			}
dvander@404
   932
		}
dvander@404
   933
		idx = pUser->next_user;
dvander@404
   934
	}
dvander@335
   935
}
dvander@335
   936
dvander@335
   937
void AdminCache::InvalidateGroupCache()
dvander@335
   938
{
dvander@335
   939
	/* Nuke the free list */
dvander@335
   940
	m_FreeGroupList = -1;
dvander@335
   941
dvander@335
   942
	/* Nuke reverse lookups */
dvander@335
   943
	sm_trie_clear(m_pGroups);
dvander@335
   944
dvander@335
   945
	/* Free memory on groups */
dvander@335
   946
	GroupId cur = m_FirstGroup;
dvander@335
   947
	AdminGroup *pGroup;
dvander@335
   948
	while (cur != INVALID_GROUP_ID)
dvander@335
   949
	{
dvander@335
   950
		pGroup = (AdminGroup *)m_pMemory->GetAddress(cur);
dvander@335
   951
		assert(pGroup->magic == GRP_MAGIC_SET);
dvander@335
   952
		if (pGroup->pCmdGrpTable)
dvander@335
   953
		{
dvander@335
   954
			sm_trie_destroy(pGroup->pCmdGrpTable);
dvander@335
   955
		}
dvander@335
   956
		if (pGroup->pCmdTable)
dvander@335
   957
		{
dvander@335
   958
			sm_trie_destroy(pGroup->pCmdTable);
dvander@335
   959
		}
dvander@335
   960
		cur = pGroup->next_grp;
dvander@335
   961
	}
dvander@335
   962
dvander@335
   963
	m_FirstGroup = INVALID_GROUP_ID;
dvander@335
   964
	m_LastGroup = INVALID_GROUP_ID;
dvander@335
   965
dvander@404
   966
	InvalidateAdminCache(false);
dvander@335
   967
dvander@335
   968
	/* Reset the memory table */
dvander@335
   969
	m_pMemory->Reset();
dvander@335
   970
}
dvander@336
   971
dvander@336
   972
void AdminCache::AddAdminListener(IAdminListener *pListener)
dvander@336
   973
{
dvander@336
   974
	m_hooks.push_back(pListener);
dvander@336
   975
}
dvander@336
   976
dvander@336
   977
void AdminCache::RemoveAdminListener(IAdminListener *pListener)
dvander@336
   978
{
dvander@336
   979
	m_hooks.remove(pListener);
dvander@336
   980
}
dvander@336
   981
dvander@404
   982
void AdminCache::RegisterAuthIdentType(const char *name)
dvander@404
   983
{
dvander@404
   984
	if (sm_trie_retrieve(m_pAuthTables, name, NULL))
dvander@404
   985
	{
dvander@404
   986
		return;
dvander@404
   987
	}
dvander@404
   988
dvander@404
   989
	Trie *pAuth = sm_trie_create();
dvander@404
   990
dvander@404
   991
	AuthMethod method;
dvander@404
   992
	method.name.assign(name);
dvander@404
   993
	method.table = pAuth;
dvander@404
   994
dvander@404
   995
	m_AuthMethods.push_back(method);
dvander@404
   996
dvander@404
   997
	sm_trie_insert(m_pAuthTables, name, pAuth);
dvander@404
   998
}
dvander@404
   999
dvander@404
  1000
void AdminCache::InvalidateAdminCache(bool unlink_admins)
dvander@404
  1001
{
dvander@458
  1002
	m_InvalidatingAdmins = true;
dvander@520
  1003
	if (!m_destroying)
dvander@520
  1004
	{
dvander@520
  1005
		g_Players.ClearAllAdmins();
dvander@520
  1006
	}
dvander@404
  1007
	/* Wipe the identity cache first */
dvander@404
  1008
	List<AuthMethod>::iterator iter;
dvander@404
  1009
	for (iter=m_AuthMethods.begin();
dvander@404
  1010
		 iter!=m_AuthMethods.end();
dvander@404
  1011
		 iter++)
dvander@404
  1012
	{
dvander@404
  1013
		sm_trie_clear((*iter).table);
dvander@404
  1014
	}
dvander@404
  1015
	
dvander@405
  1016
	if (unlink_admins)
dvander@404
  1017
	{
dvander@405
  1018
		while (m_FirstUser != INVALID_ADMIN_ID)
dvander@405
  1019
		{
dvander@405
  1020
			InvalidateAdmin(m_FirstUser);
dvander@405
  1021
		}
dvander@405
  1022
	} else {
dvander@405
  1023
		m_FirstUser = -1;
dvander@405
  1024
		m_LastUser = -1;
dvander@405
  1025
		m_FreeUserList = -1;
dvander@404
  1026
	}
dvander@458
  1027
	m_InvalidatingAdmins = false;
dvander@404
  1028
}
dvander@404
  1029
dvander@438
  1030
void AdminCache::DumpAdminCache(AdminCachePart part, bool rebuild)
dvander@336
  1031
{
dvander@438
  1032
	List<IAdminListener *>::iterator iter;
dvander@438
  1033
	IAdminListener *pListener;
dvander@438
  1034
	cell_t result;
dvander@438
  1035
dvander@438
  1036
	if (part == AdminCache_Overrides)
dvander@336
  1037
	{
dvander@336
  1038
		DumpCommandOverrideCache(Override_Command);
dvander@336
  1039
		DumpCommandOverrideCache(Override_CommandGroup);
dvander@520
  1040
		if (rebuild && !m_destroying)
dvander@438
  1041
		{
dvander@438
  1042
			for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
dvander@438
  1043
			{
dvander@438
  1044
				pListener = (*iter);
dvander@438
  1045
				pListener->OnRebuildOverrideCache();
dvander@438
  1046
			}
dvander@438
  1047
			m_pCacheFwd->PushCell(part);
dvander@438
  1048
			m_pCacheFwd->Execute(&result);
dvander@438
  1049
		}
dvander@438
  1050
	} else if (part == AdminCache_Groups || part == AdminCache_Admins) {
dvander@438
  1051
		if (part == AdminCache_Groups)
dvander@438
  1052
		{
dvander@438
  1053
			InvalidateGroupCache();
dvander@520
  1054
			if (rebuild && !m_destroying)
dvander@438
  1055
			{
dvander@438
  1056
				for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
dvander@438
  1057
				{
dvander@438
  1058
					pListener = (*iter);
dvander@438
  1059
					pListener->OnRebuildGroupCache();
dvander@438
  1060
				}
dvander@438
  1061
				m_pCacheFwd->PushCell(part);
dvander@438
  1062
				m_pCacheFwd->Execute(&result);
dvander@438
  1063
			}
dvander@438
  1064
		}
dvander@404
  1065
		InvalidateAdminCache(true);
dvander@520
  1066
		if (rebuild && !m_destroying)
dvander@336
  1067
		{
dvander@438
  1068
			for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
dvander@438
  1069
			{
dvander@438
  1070
				pListener = (*iter);
dvander@438
  1071
				pListener->OnRebuildAdminCache((part == AdminCache_Groups));
dvander@438
  1072
			}
dvander@438
  1073
			m_pCacheFwd->PushCell(AdminCache_Admins);
dvander@438
  1074
			m_pCacheFwd->Execute(&result);
dvander@1165
  1075
			g_Players.RecheckAnyAdmins();
dvander@336
  1076
		}
dvander@336
  1077
	}
dvander@336
  1078
}
dvander@404
  1079
dvander@404
  1080
const char *AdminCache::GetAdminName(AdminId id)
dvander@404
  1081
{
dvander@404
  1082
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@404
  1083
	if (!pUser || pUser->magic != USR_MAGIC_SET)
dvander@404
  1084
	{
dvander@404
  1085
		return NULL;
dvander@404
  1086
	}
dvander@404
  1087
dvander@404
  1088
	return m_pStrings->GetString(pUser->nameidx);
dvander@404
  1089
}
dvander@404
  1090
dvander@405
  1091
bool AdminCache::GetMethodIndex(const char *name, unsigned int *_index)
dvander@405
  1092
{
dvander@405
  1093
	List<AuthMethod>::iterator iter;
dvander@405
  1094
	unsigned int index = 0;
dvander@405
  1095
	for (iter=m_AuthMethods.begin();
dvander@405
  1096
		 iter!=m_AuthMethods.end();
dvander@405
  1097
		 iter++,index++)
dvander@405
  1098
	{
dvander@405
  1099
		if ((*iter).name.compare(name) == 0)
dvander@405
  1100
		{
dvander@405
  1101
			*_index = index;
dvander@405
  1102
			return true;
dvander@405
  1103
		}
dvander@405
  1104
	}
dvander@405
  1105
dvander@405
  1106
	return false;
dvander@405
  1107
}
dvander@405
  1108
dvander@404
  1109
bool AdminCache::BindAdminIdentity(AdminId id, const char *auth, const char *ident)
dvander@404
  1110
{
dvander@404
  1111
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@404
  1112
	if (!pUser || pUser->magic != USR_MAGIC_SET)
dvander@404
  1113
	{
dvander@404
  1114
		return false;
dvander@404
  1115
	}
dvander@404
  1116
dvander@404
  1117
	Trie *pTable;
dvander@404
  1118
	if (!sm_trie_retrieve(m_pAuthTables, auth, (void **)&pTable))
dvander@404
  1119
	{
dvander@404
  1120
		return false;
dvander@404
  1121
	}
dvander@404
  1122
dvander@404
  1123
	if (sm_trie_retrieve(pTable, ident, NULL))
dvander@404
  1124
	{
dvander@404
  1125
		return false;
dvander@404
  1126
	}
dvander@404
  1127
dvander@405
  1128
	pUser->auth.identidx = m_pStrings->AddString(ident);
dvander@405
  1129
	GetMethodIndex(auth, &pUser->auth.index);
dvander@405
  1130
dvander@404
  1131
	return sm_trie_insert(pTable, ident, (void **)id);
dvander@404
  1132
}
dvander@404
  1133
dvander@404
  1134
AdminId AdminCache::FindAdminByIdentity(const char *auth, const char *identity)
dvander@404
  1135
{
dvander@404
  1136
	Trie *pTable;
dvander@404
  1137
	if (!sm_trie_retrieve(m_pAuthTables, auth, (void **)&pTable))
dvander@404
  1138
	{
dvander@404
  1139
		return INVALID_ADMIN_ID;
dvander@404
  1140
	}
dvander@404
  1141
dvander@404
  1142
	void *object;
dvander@404
  1143
	if (!sm_trie_retrieve(pTable, identity, &object))
dvander@404
  1144
	{
dvander@404
  1145
		return INVALID_ADMIN_ID;
dvander@404
  1146
	}
dvander@404
  1147
dvander@404
  1148
	return (AdminId)object;
dvander@404
  1149
}
dvander@404
  1150
dvander@404
  1151
void AdminCache::SetAdminFlag(AdminId id, AdminFlag flag, bool enabled)
dvander@404
  1152
{
dvander@404
  1153
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@404
  1154
	if (!pUser || pUser->magic != USR_MAGIC_SET)
dvander@404
  1155
	{
dvander@404
  1156
		return;
dvander@404
  1157
	}
dvander@404
  1158
dvander@433
  1159
	if (flag < Admin_Reservation
dvander@404
  1160
		|| flag >= AdminFlags_TOTAL)
dvander@404
  1161
	{
dvander@404
  1162
		return;
dvander@404
  1163
	}
dvander@436
  1164
	
dvander@436
  1165
	FlagBits bits = (1<<(FlagBits)flag);
dvander@404
  1166
dvander@436
  1167
	if (enabled)
dvander@436
  1168
	{
dvander@436
  1169
		pUser->flags |= bits;
dvander@436
  1170
		pUser->eflags |= bits;
dvander@436
  1171
	} else {
dvander@436
  1172
		pUser->flags &= ~bits;
dvander@436
  1173
		pUser->eflags &= ~bits;
dvander@436
  1174
	}
dvander@404
  1175
}
dvander@404
  1176
dvander@404
  1177
bool AdminCache::GetAdminFlag(AdminId id, AdminFlag flag, AccessMode mode)
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 false;
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 false;
dvander@404
  1189
	}
dvander@404
  1190
dvander@433
  1191
	FlagBits bit = (1<<(FlagBits)flag);
dvander@433
  1192
dvander@404
  1193
	if (mode == Access_Real)
dvander@404
  1194
	{
dvander@433
  1195
		return ((pUser->flags & bit) == bit);
dvander@404
  1196
	} else if (mode == Access_Effective) {
dvander@907
  1197
		bool has_bit = ((pUser->eflags & bit) == bit);
dvander@907
  1198
		if (!has_bit && flag != Admin_Root && ((pUser->eflags & ADMFLAG_ROOT) == ADMFLAG_ROOT))
dvander@907
  1199
		{
dvander@907
  1200
			has_bit = true;
dvander@907
  1201
		}
dvander@907
  1202
		return has_bit;
dvander@404
  1203
	}
dvander@404
  1204
dvander@404
  1205
	return false;
dvander@404
  1206
}
dvander@404
  1207
dvander@433
  1208
FlagBits AdminCache::GetAdminFlags(AdminId id, AccessMode mode)
dvander@404
  1209
{
dvander@404
  1210
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@404
  1211
	if (!pUser || pUser->magic != USR_MAGIC_SET)
dvander@404
  1212
	{
dvander@404
  1213
		return 0;
dvander@404
  1214
	}
dvander@404
  1215
dvander@404
  1216
	if (mode == Access_Real)
dvander@404
  1217
	{
dvander@433
  1218
		return pUser->flags;
dvander@404
  1219
	} else if (mode == Access_Effective) {
dvander@433
  1220
		return pUser->eflags;
dvander@404
  1221
	}
dvander@404
  1222
dvander@433
  1223
	return 0;
dvander@404
  1224
}
dvander@404
  1225
dvander@458
  1226
void AdminCache::SetAdminFlags(AdminId id, AccessMode mode, FlagBits bits)
dvander@458
  1227
{
dvander@458
  1228
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@458
  1229
	if (!pUser || pUser->magic != USR_MAGIC_SET)
dvander@458
  1230
	{
dvander@458
  1231
		return;
dvander@458
  1232
	}
dvander@458
  1233
dvander@458
  1234
	if (mode == Access_Real)
dvander@458
  1235
	{
dvander@458
  1236
		pUser->flags = bits;
dvander@458
  1237
		pUser->eflags = bits;
dvander@458
  1238
	} else if (mode == Access_Effective) {
dvander@458
  1239
		pUser->eflags = bits;
dvander@458
  1240
	}
dvander@458
  1241
}
dvander@458
  1242
dvander@404
  1243
bool AdminCache::AdminInheritGroup(AdminId id, GroupId gid)
dvander@404
  1244
{
dvander@404
  1245
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@404
  1246
	if (!pUser || pUser->magic != USR_MAGIC_SET)
dvander@404
  1247
	{
dvander@404
  1248
		return false;
dvander@404
  1249
	}
dvander@404
  1250
dvander@404
  1251
	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(gid);
dvander@405
  1252
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@404
  1253
	{
dvander@404
  1254
		return false;
dvander@404
  1255
	}
dvander@404
  1256
dvander@433
  1257
	/* First check for duplicates */
dvander@433
  1258
	if (pUser->grp_count != 0)
dvander@433
  1259
	{
dvander@433
  1260
		int *temp_table = (int *)m_pMemory->GetAddress(pUser->grp_table);
dvander@433
  1261
		for (unsigned int i=0; i<pUser->grp_count; i++)
dvander@433
  1262
		{
dvander@433
  1263
			if (temp_table[i] == gid)
dvander@433
  1264
			{
dvander@433
  1265
				return false;
dvander@433
  1266
			}
dvander@433
  1267
		}
dvander@433
  1268
	}
dvander@433
  1269
dvander@404
  1270
	int *table;
dvander@404
  1271
	if (pUser->grp_count + 1 > pUser->grp_size)
dvander@404
  1272
	{
dvander@404
  1273
		int new_size = 0;
dvander@404
  1274
		int tblidx;
dvander@404
  1275
		
dvander@404
  1276
		if (pUser->grp_size == 0)
dvander@404
  1277
		{
dvander@404
  1278
			new_size = 2;
dvander@404
  1279
		} else {
dvander@404
  1280
			new_size = pUser->grp_size * 2;
dvander@404
  1281
		}
dvander@404
  1282
		
dvander@404
  1283
		/* Create and refresh pointers */
dvander@404
  1284
		tblidx = m_pMemory->CreateMem(new_size * sizeof(int), (void **)&table);
dvander@404
  1285
		pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@404
  1286
		pGroup = (AdminGroup *)m_pMemory->GetAddress(gid);
dvander@404
  1287
dvander@404
  1288
		/* Copy old data if necessary */
dvander@404
  1289
		if (pUser->grp_table != -1)
dvander@404
  1290
		{
dvander@404
  1291
			int *old_table = (int *)m_pMemory->GetAddress(pUser->grp_table);
dvander@404
  1292
			memcpy(table, old_table, sizeof(int) * pUser->grp_count);
dvander@404
  1293
		}
dvander@404
  1294
		pUser->grp_table = tblidx;
dvander@404
  1295
		pUser->grp_size = new_size;
dvander@404
  1296
	} else {
dvander@404
  1297
		table = (int *)m_pMemory->GetAddress(pUser->grp_table);
dvander@404
  1298
	}
dvander@404
  1299
dvander@404
  1300
	table[pUser->grp_count] = gid;
dvander@404
  1301
	pUser->grp_count++;
dvander@404
  1302
dvander@434
  1303
	/* Compute new effective permissions */
dvander@433
  1304
	pUser->eflags |= pGroup->addflags;
dvander@404
  1305
dvander@434
  1306
	if (pGroup->immune_default)
dvander@434
  1307
	{
dvander@434
  1308
		pUser->immune_default = true;
dvander@434
  1309
	}
dvander@434
  1310
	if (pGroup->immune_global)
dvander@434
  1311
	{
dvander@434
  1312
		pUser->immune_global = true;
dvander@434
  1313
	}
dvander@434
  1314
dvander@404
  1315
	return true;
dvander@404
  1316
}
dvander@404
  1317
dvander@458
  1318
bool AdminCache::IsValidAdmin(AdminId id)
dvander@458
  1319
{
dvander@458
  1320
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@458
  1321
	return (pUser != NULL && pUser->magic == USR_MAGIC_SET);
dvander@458
  1322
}
dvander@458
  1323
dvander@404
  1324
unsigned int AdminCache::GetAdminGroupCount(AdminId id)
dvander@404
  1325
{
dvander@404
  1326
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@404
  1327
	if (!pUser || pUser->magic != USR_MAGIC_SET)
dvander@404
  1328
	{
dvander@404
  1329
		return 0;
dvander@404
  1330
	}
dvander@404
  1331
dvander@404
  1332
	return pUser->grp_count;
dvander@404
  1333
}
dvander@404
  1334
dvander@404
  1335
GroupId AdminCache::GetAdminGroup(AdminId id, unsigned int index, const char **name)
dvander@404
  1336
{
dvander@404
  1337
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@404
  1338
	if (!pUser || pUser->magic != USR_MAGIC_SET || index >= pUser->grp_count)
dvander@404
  1339
	{
dvander@404
  1340
		return INVALID_GROUP_ID;
dvander@404
  1341
	}
dvander@404
  1342
dvander@404
  1343
	int *table = (int *)m_pMemory->GetAddress(pUser->grp_table);
dvander@404
  1344
dvander@404
  1345
	return table[index];
dvander@404
  1346
}
dvander@404
  1347
dvander@404
  1348
const char *AdminCache::GetAdminPassword(AdminId id)
dvander@404
  1349
{
dvander@404
  1350
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@404
  1351
	if (!pUser || pUser->magic != USR_MAGIC_SET)
dvander@404
  1352
	{
dvander@404
  1353
		return NULL;
dvander@404
  1354
	}
dvander@404
  1355
dvander@404
  1356
	return m_pStrings->GetString(pUser->password);
dvander@404
  1357
}
dvander@404
  1358
dvander@404
  1359
void AdminCache::SetAdminPassword(AdminId id, const char *password)
dvander@404
  1360
{	
dvander@404
  1361
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@404
  1362
	if (!pUser || pUser->magic != USR_MAGIC_SET)
dvander@404
  1363
	{
dvander@404
  1364
		return;
dvander@404
  1365
	}
dvander@404
  1366
dvander@404
  1367
	pUser->password = m_pStrings->AddString(password);
dvander@404
  1368
}
dvander@404
  1369
dvander@433
  1370
unsigned int AdminCache::FlagBitsToBitArray(FlagBits bits, bool array[], unsigned int maxSize)
dvander@433
  1371
{
dvander@433
  1372
	unsigned int i;
dvander@433
  1373
	for (i=0; i<maxSize && i<AdminFlags_TOTAL; i++)
dvander@433
  1374
	{
dvander@464
  1375
		array[i] = ((bits & (1<<i)) == (unsigned)(1<<i));
dvander@433
  1376
	}
dvander@433
  1377
dvander@433
  1378
	return i;
dvander@433
  1379
}
dvander@433
  1380
dvander@433
  1381
FlagBits AdminCache::FlagBitArrayToBits(const bool array[], unsigned int maxSize)
dvander@433
  1382
{
dvander@433
  1383
	FlagBits bits = 0;
dvander@433
  1384
	for (unsigned int i=0; i<maxSize && i<AdminFlags_TOTAL; i++)
dvander@433
  1385
	{
dvander@433
  1386
		if (array[i])
dvander@433
  1387
		{
dvander@433
  1388
			bits |= (1<<i);
dvander@433
  1389
		}
dvander@433
  1390
	}
dvander@433
  1391
dvander@433
  1392
	return bits;
dvander@433
  1393
}
dvander@433
  1394
dvander@433
  1395
FlagBits AdminCache::FlagArrayToBits(const AdminFlag array[], unsigned int numFlags)
dvander@433
  1396
{
dvander@433
  1397
	FlagBits bits = 0;
dvander@433
  1398
	for (unsigned int i=0; i<numFlags && i<AdminFlags_TOTAL; i++)
dvander@433
  1399
	{
dvander@433
  1400
		bits |= (1 << (FlagBits)array[i]);
dvander@433
  1401
	}
dvander@433
  1402
dvander@433
  1403
	return bits;
dvander@433
  1404
}
dvander@433
  1405
dvander@433
  1406
unsigned int AdminCache::FlagBitsToArray(FlagBits bits, AdminFlag array[], unsigned int maxSize)
dvander@433
  1407
{
dvander@433
  1408
	unsigned int i, num=0;
dvander@1050
  1409
	for (i=0; num<maxSize && i<AdminFlags_TOTAL; i++)
dvander@433
  1410
	{
dvander@464
  1411
		if ((bits & (1<<i)) == (unsigned)(1<<i))
dvander@433
  1412
		{
dvander@433
  1413
			array[num++] = (AdminFlag)i;
dvander@433
  1414
		}
dvander@433
  1415
	}
dvander@433
  1416
dvander@433
  1417
	return num;
dvander@433
  1418
}
dvander@434
  1419
dvander@434
  1420
bool AdminCache::CheckAdminFlags(AdminId id, FlagBits bits)
dvander@434
  1421
{
dvander@434
  1422
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@434
  1423
	if (!pUser || pUser->magic != USR_MAGIC_SET)
dvander@434
  1424
	{
dvander@434
  1425
		return false;
dvander@434
  1426
	}
dvander@434
  1427
dvander@434
  1428
	return ((pUser->eflags & bits) == bits);
dvander@434
  1429
}
dvander@434
  1430
dvander@434
  1431
bool AdminCache::CanAdminTarget(AdminId id, AdminId target)
dvander@434
  1432
{
dvander@434
  1433
	/** 
dvander@434
  1434
	 * Zeroth, if the targeting AdminId is INVALID_ADMIN_ID, targeting fails.
ds@729
  1435
	 * First, if the targeted AdminId is INVALID_ADMIN_ID, targeting succeeds.
dvander@434
  1436
	 */
dvander@434
  1437
dvander@434
  1438
	if (id == INVALID_ADMIN_ID)
dvander@434
  1439
	{
dvander@434
  1440
		return false;
dvander@434
  1441
	}
dvander@434
  1442
dvander@434
  1443
	if (target == INVALID_ADMIN_ID)
dvander@434
  1444
	{
dvander@434
  1445
		return true;
dvander@434
  1446
	}
dvander@434
  1447
dvander@434
  1448
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@434
  1449
	if (!pUser || pUser->magic != USR_MAGIC_SET)
dvander@434
  1450
	{
dvander@434
  1451
		return false;
dvander@434
  1452
	}
dvander@434
  1453
dvander@434
  1454
	AdminUser *pTarget = (AdminUser *)m_pMemory->GetAddress(target);
dvander@434
  1455
	if (!pTarget || pTarget->magic != USR_MAGIC_SET)
dvander@434
  1456
	{
dvander@434
  1457
		return false;
dvander@434
  1458
	}
dvander@434
  1459
dvander@434
  1460
	/** 
ds@729
  1461
	 * Second, if the targeting admin is root, targeting succeeds.
dvander@434
  1462
	 */
dvander@434
  1463
	if (pUser->eflags & ADMFLAG_ROOT)
dvander@434
  1464
	{
dvander@434
  1465
		return true;
dvander@434
  1466
	}
dvander@434
  1467
ds@729
  1468
	/** Fourth, if the targeted admin has global immunity, targeting fails. */
dvander@434
  1469
	if (pTarget->immune_global)
dvander@434
  1470
	{
dvander@434
  1471
		return false;
dvander@434
  1472
	}
dvander@434
  1473
dvander@434
  1474
	/** 
ds@729
  1475
	 * Fifth, if the targeted admin has default immunity 
dvander@434
  1476
	 *  and the admin belongs to no groups, targeting fails.
dvander@434
  1477
	 */
dvander@434
  1478
	if (pTarget->immune_default && pUser->grp_count < 1)
dvander@434
  1479
	{
dvander@434
  1480
		return false;
dvander@434
  1481
	}
dvander@434
  1482
dvander@434
  1483
	/** 
ds@729
  1484
	 * Sixth, if the targeted admin has specific immunity from the
dvander@434
  1485
	 *  targeting admin via group immunities, targeting fails.
dvander@434
  1486
	 */
dvander@434
  1487
	//:TODO: speed this up... maybe with trie hacks.
dvander@434
  1488
	//idea is to insert %d.%d in the trie after computing this and use it as a cache lookup.
dvander@434
  1489
	//problem is the trie cannot delete prefixes, so we'd have a problem with invalidations.
dvander@434
  1490
	if (pTarget->grp_count > 0 && pUser->grp_count > 0)
dvander@434
  1491
	{
dvander@434
  1492
		int *grp_table = (int *)m_pMemory->GetAddress(pTarget->grp_table);
dvander@434
  1493
		int *src_table = (int *)m_pMemory->GetAddress(pUser->grp_table);
dvander@434
  1494
		GroupId id, other;
dvander@434
  1495
		unsigned int num;
dvander@434
  1496
		for (unsigned int i=0; i<pTarget->grp_count; i++)
dvander@434
  1497
		{
dvander@434
  1498
			id = grp_table[i];
dvander@434
  1499
			num = GetGroupImmunityCount(id);
dvander@434
  1500
			for (unsigned int j=0; j<num; i++)
dvander@434
  1501
			{
dvander@434
  1502
				other = GetGroupImmunity(id, j);
dvander@434
  1503
				for (unsigned int k=0; k<pUser->grp_count; k++)
dvander@434
  1504
				{
dvander@434
  1505
					if (other == src_table[k])
dvander@434
  1506
					{
dvander@434
  1507
						return false;
dvander@434
  1508
					}
dvander@434
  1509
				}
dvander@434
  1510
			}
dvander@434
  1511
		}
dvander@434
  1512
	}
dvander@434
  1513
	
dvander@434
  1514
	return true;
dvander@434
  1515
}
dvander@1298
  1516
dvander@1298
  1517
bool AdminCache::FindFlag(char c, AdminFlag *pAdmFlag)
dvander@1298
  1518
{
dvander@1298
  1519
	if (c < 'a' || c > 'z')
dvander@1298
  1520
	{
dvander@1298
  1521
		return false;
dvander@1298
  1522
	}
dvander@1298
  1523
dvander@1305
  1524
	if (pAdmFlag)
dvander@1298
  1525
	{
dvander@1298
  1526
		*pAdmFlag = g_FlagLetters[(unsigned)c - (unsigned)'a'];
dvander@1298
  1527
	}
dvander@1298
  1528
dvander@1298
  1529
	return true;
dvander@1298
  1530
}
dvander@1298
  1531
dvander@1298
  1532
FlagBits AdminCache::ReadFlagString(const char *flags, const char **end)
dvander@1298
  1533
{
dvander@1298
  1534
	FlagBits bits = 0;
dvander@1298
  1535
dvander@1298
  1536
	while (flags && (*flags != '\0'))
dvander@1298
  1537
	{
dvander@1298
  1538
		AdminFlag flag;
dvander@1298
  1539
		if (!FindFlag(*flags, &flag))
dvander@1298
  1540
		{
dvander@1298
  1541
			break;
dvander@1298
  1542
		}
dvander@1298
  1543
		bits |= FlagArrayToBits(&flag, 1);
dvander@1298
  1544
		flags++;
dvander@1298
  1545
	}
dvander@1298
  1546
dvander@1298
  1547
	if (end)
dvander@1298
  1548
	{
dvander@1298
  1549
		*end = flags;
dvander@1298
  1550
	}
dvander@1298
  1551
dvander@1298
  1552
	return bits;
dvander@1298
  1553
}