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