core/AdminCache.cpp
author Liam <rbutler14@yahoo.com>
Mon Dec 29 00:31:16 2008 -0500 (2008-12-29)
changeset 2491 f16ab6fc6855
parent 2490 5701b09b3d19
child 3389 68d3e56f4bb7
permissions -rw-r--r--
Removed the if (ident==NULL) from BindAdminCache
dvander@370
     1
/**
ds@653
     2
 * vim: set ts=4 :
ds@1330
     3
 * =============================================================================
dvander@1231
     4
 * SourceMod
ds@1947
     5
 * Copyright (C) 2004-2008 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@1965
    44
#include "sm_srvcmds.h"
dvander@1298
    45
dvander@1298
    46
#define LEVEL_STATE_NONE		0
dvander@1298
    47
#define LEVEL_STATE_LEVELS		1
dvander@1298
    48
#define LEVEL_STATE_FLAGS		2
dvander@335
    49
dvander@335
    50
AdminCache g_Admins;
dvander@1965
    51
char g_ReverseFlags[26];
dvander@1298
    52
AdminFlag g_FlagLetters[26];
dvander@1298
    53
bool g_FlagSet[26];
dvander@1298
    54
dvander@1839
    55
ConVar sm_immunity_mode("sm_immunity_mode", "1", FCVAR_SPONLY, "Mode for deciding immunity protection");
dvander@1403
    56
dvander@1298
    57
/* Default flags */
dvander@1298
    58
AdminFlag g_DefaultFlags[26] = 
dvander@1298
    59
{
dvander@1298
    60
	Admin_Reservation, Admin_Generic, Admin_Kick, Admin_Ban, Admin_Unban,
dvander@1298
    61
	Admin_Slay, Admin_Changemap, Admin_Convars, Admin_Config, Admin_Chat,
dvander@1298
    62
	Admin_Vote, Admin_Password, Admin_RCON, Admin_Cheats, Admin_Custom1, 
dvander@1298
    63
	Admin_Custom2, Admin_Custom3, Admin_Custom4, Admin_Custom5, Admin_Custom6,
dvander@1298
    64
	Admin_Generic, Admin_Generic, Admin_Generic, Admin_Generic, Admin_Generic,
dvander@1298
    65
	Admin_Root
dvander@1298
    66
};
dvander@1298
    67
dvander@1298
    68
dvander@1298
    69
class FlagReader : public ITextListener_SMC
dvander@1298
    70
{
dvander@1298
    71
public:
dvander@1298
    72
	void LoadLevels()
dvander@1298
    73
	{
dvander@1298
    74
		if (!Parse())
dvander@1298
    75
		{
dvander@1298
    76
			memcpy(g_FlagLetters, g_DefaultFlags, sizeof(AdminFlag) * 26);
dvander@1298
    77
			for (unsigned int i=0; i<20; i++)
dvander@1298
    78
			{
dvander@1298
    79
				g_FlagSet[i] = true;
dvander@1298
    80
			}
dvander@1298
    81
			g_FlagSet[25] = true;
dvander@1298
    82
		}
dvander@1298
    83
	}
dvander@1298
    84
private:
dvander@1298
    85
	bool Parse()
dvander@1298
    86
	{
dvander@1656
    87
		SMCStates states;
dvander@1656
    88
		SMCError error;
dvander@1298
    89
dvander@1298
    90
		m_bFileNameLogged = false;
dvander@1298
    91
		g_SourceMod.BuildPath(Path_SM, m_File, sizeof(m_File), "configs/admin_levels.cfg");
dvander@1298
    92
dvander@1656
    93
		if ((error = textparsers->ParseFile_SMC(m_File, this, &states))
dvander@1656
    94
			!= SMCError_Okay)
dvander@1298
    95
		{
dvander@1406
    96
			const char *err_string = textparsers->GetSMCErrorString(error);
dvander@1298
    97
			if (!err_string)
dvander@1298
    98
			{
dvander@1298
    99
				err_string = "Unknown error";
dvander@1298
   100
			}
dvander@1656
   101
			ParseError(NULL, "Error %d (%s)", error, err_string);
dvander@1298
   102
			return false;
dvander@1298
   103
		}
dvander@1298
   104
dvander@1298
   105
		return true;
dvander@1298
   106
	}
dvander@1298
   107
	void ReadSMC_ParseStart()
dvander@1298
   108
	{
dvander@1298
   109
		m_LevelState = LEVEL_STATE_NONE;
dvander@1298
   110
		m_IgnoreLevel = 0;
dvander@1298
   111
		memset(g_FlagSet, 0, sizeof(g_FlagSet));
dvander@1298
   112
	}
dvander@1656
   113
	SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name)
dvander@1298
   114
	{
dvander@1298
   115
		if (m_IgnoreLevel)
dvander@1298
   116
		{
dvander@1298
   117
			m_IgnoreLevel++;
dvander@1656
   118
			return SMCResult_Continue;
dvander@1298
   119
		}
dvander@1298
   120
dvander@1298
   121
		if (m_LevelState == LEVEL_STATE_NONE)
dvander@1298
   122
		{
dvander@1298
   123
			if (strcmp(name, "Levels") == 0)
dvander@1298
   124
			{
dvander@1299
   125
				m_LevelState = LEVEL_STATE_LEVELS;
dvander@1656
   126
			} 
dvander@1656
   127
			else 
dvander@1656
   128
			{
dvander@1298
   129
				m_IgnoreLevel++;
dvander@1298
   130
			}
dvander@1299
   131
		} else if (m_LevelState == LEVEL_STATE_LEVELS) {
dvander@1298
   132
			if (strcmp(name, "Flags") == 0)
dvander@1298
   133
			{
dvander@1299
   134
				m_LevelState = LEVEL_STATE_FLAGS;
dvander@1656
   135
			} 
dvander@1656
   136
			else 
dvander@1656
   137
			{
dvander@1298
   138
				m_IgnoreLevel++;
dvander@1298
   139
			}
dvander@1656
   140
		} 
dvander@1656
   141
		else 
dvander@1656
   142
		{
dvander@1298
   143
			m_IgnoreLevel++;
dvander@1298
   144
		}
dvander@1298
   145
dvander@1656
   146
		return SMCResult_Continue;
dvander@1298
   147
	}
dvander@1656
   148
	SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value)
dvander@1298
   149
	{
dvander@1299
   150
		if (m_LevelState != LEVEL_STATE_FLAGS || m_IgnoreLevel)
dvander@1298
   151
		{
dvander@1656
   152
			return SMCResult_Continue;
dvander@1298
   153
		}
dvander@1298
   154
dvander@1298
   155
		unsigned char c = (unsigned)value[0];
dvander@1298
   156
dvander@1298
   157
		if (c < (unsigned)'a' || c > (unsigned)'z')
dvander@1298
   158
		{
dvander@1656
   159
			ParseError(states, "Flag \"%c\" is not a lower-case ASCII letter", c);
dvander@1656
   160
			return SMCResult_Continue;
dvander@1298
   161
		}
dvander@1298
   162
dvander@1298
   163
		c -= (unsigned)'a';
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@1965
   302
	int i;
dvander@1965
   303
	AdminFlag flag;
dvander@1965
   304
dvander@1298
   305
	/* For now, we only read these once per level. */
dvander@1298
   306
	s_FlagReader.LoadLevels();
dvander@1965
   307
dvander@1965
   308
	for (i = 0; i < 26; i++)
dvander@1965
   309
	{
dvander@1965
   310
		if (FindFlag('a' + i, &flag))
dvander@1965
   311
		{
dvander@1965
   312
			g_ReverseFlags[flag] = 'a' + i;
dvander@1965
   313
		}
dvander@1965
   314
		else
dvander@1965
   315
		{
dvander@1965
   316
			g_ReverseFlags[flag] = '?';
dvander@1965
   317
		}
dvander@1965
   318
	}
dvander@1298
   319
}
dvander@1298
   320
dvander@336
   321
void AdminCache::OnSourceModShutdown()
dvander@336
   322
{
dvander@336
   323
	g_Forwards.ReleaseForward(m_pCacheFwd);
dvander@336
   324
	m_pCacheFwd = NULL;
dvander@336
   325
}
dvander@336
   326
dvander@673
   327
void AdminCache::OnSourceModPluginsLoaded()
dvander@673
   328
{
dvander@673
   329
	DumpAdminCache(AdminCache_Overrides, true);
dvander@673
   330
	DumpAdminCache(AdminCache_Groups, true);
dvander@673
   331
}
dvander@673
   332
dvander@1298
   333
void AdminCache::NameFlag(const char *str, AdminFlag flag)
dvander@1298
   334
{
dvander@1298
   335
	sm_trie_insert(m_pLevelNames, str, (void *)flag);
dvander@1298
   336
}
dvander@1298
   337
dvander@1298
   338
bool AdminCache::FindFlag(const char *str, AdminFlag *pFlag)
dvander@1298
   339
{
dvander@1298
   340
	void *obj;
dvander@1298
   341
	if (!sm_trie_retrieve(m_pLevelNames, str, &obj))
dvander@1298
   342
	{
dvander@1298
   343
		return false;
dvander@1298
   344
	}
dvander@1298
   345
dvander@1298
   346
	if (pFlag)
dvander@1298
   347
	{
dvander@1298
   348
		*pFlag = (AdminFlag)(int)obj;
dvander@1298
   349
	}
dvander@1298
   350
dvander@1298
   351
	return true;
dvander@1298
   352
}
dvander@1298
   353
dvander@433
   354
void AdminCache::AddCommandOverride(const char *cmd, OverrideType type, FlagBits flags)
dvander@335
   355
{
dvander@433
   356
	Trie *pTrie = NULL;
dvander@335
   357
	if (type == Override_Command)
dvander@335
   358
	{
dvander@433
   359
		pTrie = m_pCmdOverrides;
dvander@335
   360
	} else if (type == Override_CommandGroup) {
dvander@433
   361
		pTrie = m_pCmdGrpOverrides;
dvander@433
   362
	} else {
dvander@433
   363
		return;
dvander@335
   364
	}
dvander@433
   365
dvander@433
   366
	sm_trie_insert(pTrie, cmd, (void *)(unsigned int)flags);
dvander@514
   367
dvander@1435
   368
	g_ConCmds.UpdateAdminCmdFlags(cmd, type, flags, false);
dvander@335
   369
}
dvander@335
   370
dvander@433
   371
bool AdminCache::GetCommandOverride(const char *cmd, OverrideType type, FlagBits *pFlags)
dvander@335
   372
{
dvander@433
   373
	Trie *pTrie = NULL;
dvander@433
   374
dvander@335
   375
	if (type == Override_Command)
dvander@335
   376
	{
dvander@433
   377
		pTrie = m_pCmdOverrides;
dvander@335
   378
	} else if (type == Override_CommandGroup) {
dvander@433
   379
		pTrie = m_pCmdGrpOverrides;
dvander@433
   380
	} else {
dvander@433
   381
		return false;
dvander@433
   382
	}
dvander@433
   383
dvander@433
   384
	void *object;
dvander@433
   385
	if (sm_trie_retrieve(pTrie, cmd, &object))
dvander@433
   386
	{
dvander@433
   387
		if (pFlags)
dvander@433
   388
		{
dvander@433
   389
			*pFlags = (FlagBits)object;
dvander@433
   390
		}
dvander@433
   391
		return true;
dvander@335
   392
	}
dvander@335
   393
dvander@335
   394
	return false;
dvander@335
   395
}
dvander@335
   396
dvander@335
   397
void AdminCache::UnsetCommandOverride(const char *cmd, OverrideType type)
dvander@335
   398
{
dvander@335
   399
	if (type == Override_Command)
dvander@335
   400
	{
dvander@335
   401
		return _UnsetCommandOverride(cmd);
dvander@335
   402
	} else if (type == Override_CommandGroup) {
dvander@335
   403
		return _UnsetCommandGroupOverride(cmd);
dvander@335
   404
	}
dvander@335
   405
}
dvander@335
   406
dvander@335
   407
void AdminCache::_UnsetCommandGroupOverride(const char *group)
dvander@335
   408
{
dvander@335
   409
	if (!m_pCmdGrpOverrides)
dvander@335
   410
	{
dvander@335
   411
		return;
dvander@335
   412
	}
dvander@335
   413
dvander@514
   414
	sm_trie_delete(m_pCmdGrpOverrides, group);
dvander@335
   415
dvander@1435
   416
	g_ConCmds.UpdateAdminCmdFlags(group, Override_CommandGroup, 0, true);
dvander@335
   417
}
dvander@335
   418
dvander@335
   419
void AdminCache::_UnsetCommandOverride(const char *cmd)
dvander@335
   420
{
dvander@335
   421
	if (!m_pCmdOverrides)
dvander@335
   422
	{
dvander@335
   423
		return;
dvander@335
   424
	}
dvander@335
   425
dvander@514
   426
	sm_trie_delete(m_pCmdOverrides, cmd);
dvander@335
   427
dvander@1435
   428
	g_ConCmds.UpdateAdminCmdFlags(cmd, Override_Command, 0, true);
dvander@335
   429
}
dvander@335
   430
dvander@335
   431
void AdminCache::DumpCommandOverrideCache(OverrideType type)
dvander@335
   432
{
dvander@335
   433
	if (type == Override_Command && m_pCmdOverrides)
dvander@335
   434
	{
dvander@335
   435
		sm_trie_clear(m_pCmdOverrides);
dvander@335
   436
	} else if (type == Override_CommandGroup && m_pCmdGrpOverrides) {
dvander@335
   437
		sm_trie_clear(m_pCmdGrpOverrides);
dvander@335
   438
	}
dvander@335
   439
}
dvander@335
   440
dvander@404
   441
AdminId AdminCache::CreateAdmin(const char *name)
dvander@404
   442
{
dvander@404
   443
	AdminId id;
dvander@404
   444
	AdminUser *pUser;
dvander@404
   445
dvander@404
   446
	if (m_FreeUserList != INVALID_ADMIN_ID)
dvander@404
   447
	{
dvander@404
   448
		pUser = (AdminUser *)m_pMemory->GetAddress(m_FreeUserList);
dvander@404
   449
		assert(pUser->magic == USR_MAGIC_UNSET);
dvander@404
   450
		id = m_FreeUserList;
dvander@404
   451
		m_FreeUserList = pUser->next_user;
dvander@1965
   452
	}
dvander@1965
   453
	else
dvander@1965
   454
	{
dvander@404
   455
		id = m_pMemory->CreateMem(sizeof(AdminUser), (void **)&pUser);
dvander@404
   456
		pUser->grp_size = 0;
dvander@404
   457
		pUser->grp_table = -1;
dvander@404
   458
	}
dvander@404
   459
dvander@433
   460
	pUser->flags = 0;
dvander@433
   461
	pUser->eflags = 0;
dvander@404
   462
	pUser->grp_count = 0;
dvander@404
   463
	pUser->password = -1;
dvander@404
   464
	pUser->magic = USR_MAGIC_SET;
dvander@405
   465
	pUser->auth.identidx = -1;
dvander@405
   466
	pUser->auth.index = 0;
dvander@1403
   467
	pUser->immunity_level = 0;
dvander@1349
   468
	pUser->serialchange = 1;
dvander@404
   469
dvander@404
   470
	if (m_FirstUser == INVALID_ADMIN_ID)
dvander@404
   471
	{
dvander@404
   472
		m_FirstUser = id;
dvander@404
   473
		m_LastUser = id;
dvander@1965
   474
	}
dvander@1965
   475
	else
dvander@1965
   476
	{
dvander@404
   477
		AdminUser *pPrev = (AdminUser *)m_pMemory->GetAddress(m_LastUser);
dvander@404
   478
		pPrev->next_user = id;
dvander@404
   479
		pUser->prev_user = m_LastUser;
dvander@404
   480
		m_LastUser = id;
dvander@404
   481
	}
dvander@404
   482
dvander@1965
   483
	/* Since we always append to the tail, we should invalidate their next */
dvander@1965
   484
	pUser->next_user = -1;
dvander@1965
   485
dvander@404
   486
	if (name && name[0] != '\0')
dvander@404
   487
	{
dvander@1356
   488
		int nameidx = m_pStrings->AddString(name);
dvander@1356
   489
		pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@1356
   490
		pUser->nameidx = nameidx;
dvander@404
   491
	}
dvander@1965
   492
	else
dvander@1965
   493
	{
dvander@1965
   494
		pUser->nameidx = -1;
dvander@1965
   495
	}
dvander@404
   496
dvander@404
   497
	return id;
dvander@404
   498
}
dvander@404
   499
dvander@335
   500
GroupId AdminCache::AddGroup(const char *group_name)
dvander@335
   501
{
dvander@335
   502
	if (sm_trie_retrieve(m_pGroups, group_name, NULL))
dvander@335
   503
	{
dvander@335
   504
		return INVALID_GROUP_ID;
dvander@335
   505
	}
dvander@335
   506
dvander@335
   507
	GroupId id;
dvander@335
   508
	AdminGroup *pGroup;
dvander@335
   509
	if (m_FreeGroupList != INVALID_GROUP_ID)
dvander@335
   510
	{
dvander@335
   511
		pGroup = (AdminGroup *)m_pMemory->GetAddress(m_FreeGroupList);
dvander@335
   512
		assert(pGroup->magic == GRP_MAGIC_UNSET);
dvander@335
   513
		id = m_FreeGroupList;
dvander@335
   514
		m_FreeGroupList = pGroup->next_grp;
dvander@335
   515
	} else {
dvander@335
   516
		id = m_pMemory->CreateMem(sizeof(AdminGroup), (void **)&pGroup);
dvander@335
   517
	}
dvander@335
   518
dvander@1403
   519
	pGroup->immunity_level = 0;
dvander@335
   520
	pGroup->immune_table = -1;
dvander@335
   521
	pGroup->magic = GRP_MAGIC_SET;
dvander@335
   522
	pGroup->next_grp = INVALID_GROUP_ID;
dvander@335
   523
	pGroup->pCmdGrpTable = NULL;
dvander@335
   524
	pGroup->pCmdTable = NULL;
dvander@433
   525
	pGroup->addflags = 0;
dvander@335
   526
dvander@335
   527
	if (m_FirstGroup == INVALID_GROUP_ID)
dvander@335
   528
	{
dvander@335
   529
		m_FirstGroup = id;
dvander@335
   530
		m_LastGroup = id;
dvander@335
   531
		pGroup->prev_grp = INVALID_GROUP_ID;
dvander@335
   532
	} else {
dvander@335
   533
		AdminGroup *pPrev = (AdminGroup *)m_pMemory->GetAddress(m_LastGroup);
dvander@335
   534
		assert(pPrev->magic == GRP_MAGIC_SET);
dvander@335
   535
		pPrev->next_grp = id;
dvander@335
   536
		pGroup->prev_grp = m_LastGroup;
dvander@335
   537
		m_LastGroup = id;
dvander@335
   538
	}
dvander@335
   539
dvander@1356
   540
	int nameidx = m_pStrings->AddString(group_name);
dvander@1356
   541
	pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
dvander@1356
   542
	pGroup->nameidx = nameidx;
dvander@404
   543
dvander@335
   544
	sm_trie_insert(m_pGroups, group_name, (void *)id);
dvander@335
   545
dvander@335
   546
	return id;
dvander@335
   547
}
dvander@335
   548
dvander@335
   549
GroupId AdminCache::FindGroupByName(const char *group_name)
dvander@335
   550
{
dvander@335
   551
	void *object;
dvander@335
   552
dvander@335
   553
	if (!sm_trie_retrieve(m_pGroups, group_name, &object))
dvander@335
   554
	{
dvander@335
   555
		return INVALID_GROUP_ID;
dvander@335
   556
	}
dvander@335
   557
dvander@335
   558
	GroupId id = (GroupId)object;
dvander@335
   559
	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
dvander@335
   560
dvander@335
   561
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@335
   562
	{
dvander@335
   563
		return INVALID_GROUP_ID;
dvander@335
   564
	}
dvander@335
   565
dvander@335
   566
	return id;
dvander@335
   567
}
dvander@335
   568
dvander@335
   569
void AdminCache::SetGroupAddFlag(GroupId id, AdminFlag flag, bool enabled)
dvander@335
   570
{
dvander@335
   571
	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
dvander@335
   572
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@335
   573
	{
dvander@335
   574
		return;
dvander@335
   575
	}
dvander@335
   576
dvander@433
   577
	if (flag < Admin_Reservation || flag >= AdminFlags_TOTAL)
dvander@335
   578
	{
dvander@335
   579
		return;
dvander@335
   580
	}
dvander@335
   581
dvander@436
   582
	FlagBits bits = (1<<(FlagBits)flag);
dvander@436
   583
dvander@436
   584
	if (enabled)
dvander@436
   585
	{
dvander@436
   586
		pGroup->addflags |= bits;
dvander@436
   587
	} else {
dvander@436
   588
		pGroup->addflags &= ~bits;
dvander@436
   589
	}
dvander@335
   590
}
dvander@335
   591
dvander@335
   592
bool AdminCache::GetGroupAddFlag(GroupId id, AdminFlag flag)
dvander@335
   593
{
dvander@335
   594
	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
dvander@335
   595
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@335
   596
	{
dvander@335
   597
		return false;
dvander@335
   598
	}
dvander@335
   599
dvander@433
   600
	if (flag < Admin_Reservation || flag >= AdminFlags_TOTAL)
dvander@335
   601
	{
dvander@335
   602
		return false;
dvander@335
   603
	}
dvander@335
   604
dvander@433
   605
	FlagBits bit = 1<<(FlagBits)flag;
dvander@433
   606
	return ((pGroup->addflags & bit) == bit);
dvander@335
   607
}
dvander@335
   608
dvander@433
   609
FlagBits AdminCache::GetGroupAddFlags(GroupId id)
dvander@335
   610
{
dvander@335
   611
	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
dvander@335
   612
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@335
   613
	{
dvander@335
   614
		return 0;
dvander@335
   615
	}
dvander@335
   616
dvander@433
   617
	return pGroup->addflags;
dvander@335
   618
}
dvander@335
   619
dvander@1356
   620
const char *AdminCache::GetGroupName(GroupId gid)
dvander@1356
   621
{
dvander@1356
   622
	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(gid);
dvander@1356
   623
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@1356
   624
	{
dvander@1403
   625
		return NULL;
dvander@1356
   626
	}
dvander@1356
   627
dvander@1356
   628
	return m_pStrings->GetString(pGroup->nameidx);
dvander@1356
   629
}
dvander@1356
   630
dvander@335
   631
void AdminCache::SetGroupGenericImmunity(GroupId id, ImmunityType type, bool enabled)
dvander@335
   632
{
dvander@335
   633
	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
dvander@335
   634
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@335
   635
	{
dvander@335
   636
		return;
dvander@335
   637
	}
dvander@335
   638
dvander@1403
   639
	unsigned int level = 0;
dvander@1403
   640
dvander@1403
   641
	if (enabled)
dvander@335
   642
	{
dvander@1403
   643
		if (type == Immunity_Default)
dvander@1403
   644
		{
dvander@1403
   645
			level = 1;
dvander@1403
   646
		} else if (type == Immunity_Global) {
dvander@1403
   647
			level = 2;
dvander@1403
   648
		}
dvander@1403
   649
		if (level > pGroup->immunity_level)
dvander@1403
   650
		{
dvander@1403
   651
			pGroup->immunity_level = level;
dvander@1403
   652
		}
dvander@1403
   653
	} else {
dvander@1403
   654
		pGroup->immunity_level = 0;
dvander@1403
   655
	}
dvander@335
   656
}
dvander@335
   657
dvander@335
   658
bool AdminCache::GetGroupGenericImmunity(GroupId id, ImmunityType type)
dvander@335
   659
{
dvander@335
   660
	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
dvander@335
   661
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@335
   662
	{
dvander@335
   663
		return false;
dvander@335
   664
	}
dvander@335
   665
dvander@1403
   666
	if (type == Immunity_Default && pGroup->immunity_level >= 1)
dvander@335
   667
	{
dvander@1403
   668
		return true;
dvander@1403
   669
	} else if (type == Immunity_Global && pGroup->immunity_level >= 2) {
dvander@1403
   670
		return true;
dvander@335
   671
	}
dvander@335
   672
dvander@335
   673
	return false;
dvander@335
   674
}
dvander@335
   675
dvander@335
   676
void AdminCache::AddGroupImmunity(GroupId id, GroupId other_id)
dvander@335
   677
{
dvander@1356
   678
	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(other_id);
dvander@335
   679
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@335
   680
	{
dvander@335
   681
		return;
dvander@335
   682
	}
dvander@335
   683
dvander@1356
   684
	pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
dvander@1356
   685
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@335
   686
	{
dvander@335
   687
		return;
dvander@335
   688
	}
dvander@335
   689
dvander@335
   690
	/* We always need to resize the immunity table */
dvander@335
   691
	int *table, tblidx;
dvander@1356
   692
	if (pGroup->immune_table == -1)
dvander@335
   693
	{
dvander@335
   694
		tblidx = m_pMemory->CreateMem(sizeof(int) * 2, (void **)&table);
dvander@1356
   695
		pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
dvander@335
   696
		table[0] = 0;
dvander@335
   697
	} else {
dvander@1356
   698
		int *old_table = (int *)m_pMemory->GetAddress(pGroup->immune_table);
dvander@433
   699
		/* Break out if this group is already in the list */
dvander@433
   700
		for (int i=0; i<old_table[0]; i++)
dvander@433
   701
		{
dvander@433
   702
			if (old_table[1+i] == other_id)
dvander@433
   703
			{
dvander@433
   704
				return;
dvander@433
   705
			}
dvander@433
   706
		}
dvander@335
   707
		tblidx = m_pMemory->CreateMem(sizeof(int) * (old_table[0] + 2), (void **)&table);
dvander@433
   708
		/* Get the old address again in case of resize */
dvander@1356
   709
		pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
dvander@1356
   710
		old_table = (int *)m_pMemory->GetAddress(pGroup->immune_table);
dvander@335
   711
		table[0] = old_table[0];
dvander@335
   712
		for (unsigned int i=1; i<=(unsigned int)old_table[0]; i++)
dvander@335
   713
		{
dvander@335
   714
			table[i] = old_table[i];
dvander@335
   715
		}
dvander@335
   716
	}
dvander@335
   717
dvander@335
   718
	/* Assign */
dvander@1356
   719
	pGroup->immune_table = tblidx;
dvander@335
   720
dvander@335
   721
	/* Add to the array */
dvander@335
   722
	table[0]++;
dvander@335
   723
	table[table[0]] = other_id;
dvander@335
   724
}
dvander@335
   725
dvander@335
   726
unsigned int AdminCache::GetGroupImmunityCount(GroupId id)
dvander@335
   727
{
dvander@335
   728
	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
dvander@335
   729
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@335
   730
	{
dvander@335
   731
		return 0;
dvander@335
   732
	}
dvander@335
   733
dvander@335
   734
	if (pGroup->immune_table == -1)
dvander@335
   735
	{
dvander@335
   736
		return 0;
dvander@335
   737
	}
dvander@335
   738
dvander@335
   739
	int *table = (int *)m_pMemory->GetAddress(pGroup->immune_table);
dvander@335
   740
dvander@335
   741
	return table[0];
dvander@335
   742
}
dvander@335
   743
dvander@335
   744
GroupId AdminCache::GetGroupImmunity(GroupId id, unsigned int number)
dvander@335
   745
{
dvander@335
   746
	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
dvander@335
   747
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@335
   748
	{
dvander@335
   749
		return INVALID_GROUP_ID;
dvander@335
   750
	}
dvander@335
   751
dvander@335
   752
	if (pGroup->immune_table == -1)
dvander@335
   753
	{
dvander@335
   754
		return INVALID_GROUP_ID;
dvander@335
   755
	}
dvander@335
   756
dvander@335
   757
	int *table = (int *)m_pMemory->GetAddress(pGroup->immune_table);
dvander@335
   758
	if (number >= (unsigned int)table[0])
dvander@335
   759
	{
dvander@335
   760
		return INVALID_GROUP_ID;
dvander@335
   761
	}
dvander@335
   762
dvander@335
   763
	return table[1 + number];
dvander@335
   764
}
dvander@335
   765
dvander@335
   766
void AdminCache::AddGroupCommandOverride(GroupId id, const char *name, OverrideType type, OverrideRule rule)
dvander@335
   767
{
dvander@335
   768
	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
dvander@335
   769
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@335
   770
	{
dvander@335
   771
		return;
dvander@335
   772
	}
dvander@335
   773
dvander@335
   774
	Trie *pTrie = NULL;
dvander@335
   775
	if (type == Override_Command)
dvander@335
   776
	{
dvander@335
   777
		if (pGroup->pCmdTable == NULL)
dvander@335
   778
		{
dvander@335
   779
			pGroup->pCmdTable = sm_trie_create();
dvander@335
   780
		}
dvander@335
   781
		pTrie = pGroup->pCmdTable;
dvander@335
   782
	} else if (type == Override_CommandGroup) {
dvander@335
   783
		if (pGroup->pCmdGrpTable == NULL)
dvander@335
   784
		{
dvander@335
   785
			pGroup->pCmdGrpTable = sm_trie_create();
dvander@335
   786
		}
dvander@335
   787
		pTrie = pGroup->pCmdGrpTable;
dvander@335
   788
	} else {
dvander@335
   789
		return;
dvander@335
   790
	}
dvander@335
   791
dvander@335
   792
	sm_trie_insert(pTrie, name, (void *)(int)rule);
dvander@335
   793
}
dvander@335
   794
dvander@335
   795
bool AdminCache::GetGroupCommandOverride(GroupId id, const char *name, OverrideType type, OverrideRule *pRule)
dvander@335
   796
{
dvander@335
   797
	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
dvander@335
   798
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@335
   799
	{
dvander@335
   800
		return false;
dvander@335
   801
	}
dvander@335
   802
dvander@335
   803
	Trie *pTrie = NULL;
dvander@335
   804
	if (type == Override_Command)
dvander@335
   805
	{
dvander@335
   806
		if (pGroup->pCmdTable == NULL)
dvander@335
   807
		{
dvander@335
   808
			return false;
dvander@335
   809
		}
dvander@335
   810
		pTrie = pGroup->pCmdTable;
dvander@335
   811
	} else if (type == Override_CommandGroup) {
dvander@335
   812
		if (pGroup->pCmdGrpTable == NULL)
dvander@335
   813
		{
dvander@335
   814
			return false;
dvander@335
   815
		}
dvander@335
   816
		pTrie = pGroup->pCmdGrpTable;
dvander@335
   817
	} else {
dvander@335
   818
		return false;
dvander@335
   819
	}
dvander@335
   820
dvander@335
   821
	void *object;
dvander@335
   822
	if (!sm_trie_retrieve(pTrie, name, &object))
dvander@335
   823
	{
dvander@335
   824
		return false;
dvander@335
   825
	}
dvander@335
   826
dvander@335
   827
	if (pRule)
dvander@335
   828
	{
dvander@335
   829
		*pRule = (OverrideRule)(int)object;
dvander@335
   830
	}
dvander@335
   831
	
dvander@335
   832
	return true;
dvander@335
   833
}
dvander@335
   834
dvander@404
   835
Trie *AdminCache::GetMethodByIndex(unsigned int index)
dvander@404
   836
{
dvander@404
   837
	List<AuthMethod>::iterator iter;
dvander@404
   838
	for (iter=m_AuthMethods.begin();
dvander@404
   839
		 iter!=m_AuthMethods.end();
dvander@404
   840
		 iter++)
dvander@404
   841
	{
dvander@404
   842
		if (index-- == 0)
dvander@404
   843
		{
dvander@404
   844
			return (*iter).table;
dvander@404
   845
		}
dvander@404
   846
	}
dvander@404
   847
dvander@404
   848
	return NULL;
dvander@404
   849
}
dvander@404
   850
dvander@404
   851
bool AdminCache::InvalidateAdmin(AdminId id)
dvander@404
   852
{
dvander@404
   853
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@404
   854
	AdminUser *pOther;
dvander@404
   855
	if (!pUser || pUser->magic != USR_MAGIC_SET)
dvander@404
   856
	{
dvander@404
   857
		return false;
dvander@404
   858
	}
dvander@404
   859
dvander@520
   860
	if (!m_InvalidatingAdmins && !m_destroying)
dvander@458
   861
	{
dvander@458
   862
		g_Players.ClearAdminId(id);
dvander@458
   863
	}
dvander@458
   864
dvander@404
   865
	/* Unlink from the dbl link list */
dvander@404
   866
	if (id == m_FirstUser && id == m_LastUser)
dvander@404
   867
	{
dvander@404
   868
		m_FirstUser = INVALID_ADMIN_ID;
dvander@404
   869
		m_LastUser = INVALID_ADMIN_ID;
dvander@404
   870
	} else if (id == m_FirstUser) {
dvander@404
   871
		m_FirstUser = pUser->next_user;
dvander@404
   872
		pOther = (AdminUser *)m_pMemory->GetAddress(m_FirstUser);
dvander@404
   873
		pOther->prev_user = INVALID_ADMIN_ID;
dvander@404
   874
	} else if (id == m_LastUser) {
dvander@404
   875
		m_LastUser = pUser->prev_user;
dvander@404
   876
		pOther = (AdminUser *)m_pMemory->GetAddress(m_LastUser);
dvander@404
   877
		pOther->next_user = INVALID_ADMIN_ID;
dvander@404
   878
	} else {
dvander@404
   879
		pOther = (AdminUser *)m_pMemory->GetAddress(pUser->prev_user);
dvander@404
   880
		pOther->next_user = pUser->next_user;
dvander@404
   881
		pOther = (AdminUser *)m_pMemory->GetAddress(pUser->next_user);
dvander@404
   882
		pOther->prev_user = pUser->prev_user;
dvander@404
   883
	}
dvander@404
   884
dvander@404
   885
	/* Unlink from auth tables */
dvander@405
   886
	if (pUser->auth.identidx != -1)
dvander@404
   887
	{
dvander@405
   888
		Trie *pTrie = GetMethodByIndex(pUser->auth.index);
dvander@405
   889
		if (pTrie)
dvander@404
   890
		{
dvander@405
   891
			sm_trie_delete(pTrie, m_pStrings->GetString(pUser->auth.identidx));
dvander@404
   892
		}
dvander@404
   893
	}
dvander@404
   894
dvander@404
   895
	/* Clear table counts */
dvander@404
   896
	pUser->grp_count = 0;
dvander@405
   897
	
dvander@404
   898
	/* Link into free list */
dvander@404
   899
	pUser->magic = USR_MAGIC_UNSET;
dvander@404
   900
	pUser->next_user = m_FreeUserList;
dvander@404
   901
	m_FreeUserList = id;
dvander@404
   902
dvander@1349
   903
	/* Unset serial change */
dvander@1349
   904
	pUser->serialchange = 0;
dvander@1349
   905
dvander@404
   906
	return true;
dvander@404
   907
}
dvander@404
   908
dvander@404
   909
dvander@335
   910
void AdminCache::InvalidateGroup(GroupId id)
dvander@335
   911
{
dvander@335
   912
	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
dvander@335
   913
	AdminGroup *pOther;
dvander@335
   914
dvander@335
   915
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@335
   916
	{
dvander@335
   917
		return;
dvander@335
   918
	}
dvander@335
   919
dvander@335
   920
	const char *str = m_pStrings->GetString(pGroup->nameidx);
dvander@335
   921
	sm_trie_delete(m_pGroups, str);
dvander@335
   922
dvander@335
   923
	/* Unlink from the live dbllink list */
dvander@335
   924
	if (id == m_FirstGroup && id == m_LastGroup)
dvander@335
   925
	{
dvander@335
   926
		m_LastGroup = INVALID_GROUP_ID;
dvander@335
   927
		m_FirstGroup = INVALID_GROUP_ID;
dvander@335
   928
	} else if (id == m_FirstGroup) {
dvander@335
   929
		m_FirstGroup = pGroup->next_grp;
dvander@335
   930
		pOther = (AdminGroup *)m_pMemory->GetAddress(m_FirstGroup);
dvander@335
   931
		pOther->prev_grp = INVALID_GROUP_ID;
dvander@335
   932
	} else if (id == m_LastGroup) {
dvander@335
   933
		m_LastGroup = pGroup->prev_grp;
dvander@335
   934
		pOther = (AdminGroup *)m_pMemory->GetAddress(m_LastGroup);
dvander@335
   935
		pOther->next_grp = INVALID_GROUP_ID;
dvander@335
   936
	} else {
dvander@335
   937
		pOther = (AdminGroup *)m_pMemory->GetAddress(pGroup->prev_grp);
dvander@335
   938
		pOther->next_grp = pGroup->next_grp;
dvander@335
   939
		pOther = (AdminGroup *)m_pMemory->GetAddress(pGroup->next_grp);
dvander@335
   940
		pOther->prev_grp = pGroup->prev_grp;
dvander@335
   941
	}
dvander@335
   942
dvander@335
   943
	/* Free any used memory to be safe */
dvander@335
   944
	if (pGroup->pCmdGrpTable)
dvander@335
   945
	{
dvander@335
   946
		sm_trie_destroy(pGroup->pCmdGrpTable);
dvander@335
   947
		pGroup->pCmdGrpTable = NULL;
dvander@335
   948
	}
dvander@335
   949
	if (pGroup->pCmdTable)
dvander@335
   950
	{
dvander@335
   951
		sm_trie_destroy(pGroup->pCmdTable);
dvander@335
   952
		pGroup->pCmdTable = NULL;
dvander@335
   953
	}
dvander@335
   954
dvander@335
   955
	/* Link into the free list */
dvander@335
   956
	pGroup->magic = GRP_MAGIC_UNSET;
dvander@335
   957
	pGroup->next_grp = m_FreeGroupList;
dvander@335
   958
	m_FreeGroupList = id;
dvander@335
   959
dvander@404
   960
	int idx = m_FirstUser;
dvander@404
   961
	AdminUser *pUser;
dvander@404
   962
	int *table;
dvander@404
   963
	while (idx != INVALID_ADMIN_ID)
dvander@404
   964
	{
dvander@404
   965
		pUser = (AdminUser *)m_pMemory->GetAddress(idx);
dvander@404
   966
		if (pUser->grp_count > 0)
dvander@404
   967
		{
dvander@404
   968
			table = (int *)m_pMemory->GetAddress(pUser->grp_table);
dvander@404
   969
			for (unsigned int i=0; i<pUser->grp_count; i++)
dvander@404
   970
			{
dvander@404
   971
				if (table[i] == id)
dvander@404
   972
				{
dvander@404
   973
					/* We have to remove this entry */
dvander@404
   974
					for (unsigned int j=i+1; j<pUser->grp_count; j++)
dvander@404
   975
					{
dvander@404
   976
						/* Move everything down by one */
dvander@404
   977
						table[j-1] = table[j];
dvander@404
   978
					}
dvander@404
   979
					/* Decrease count */
dvander@404
   980
					pUser->grp_count--;
dvander@404
   981
					/* Recalculate effective flags */
dvander@433
   982
					pUser->eflags = pUser->flags;
dvander@404
   983
					for (unsigned int j=0; j<pUser->grp_count; j++)
dvander@404
   984
					{
dvander@404
   985
						pOther = (AdminGroup *)m_pMemory->GetAddress(table[j]);
dvander@433
   986
						pUser->eflags |= pOther->addflags;
dvander@404
   987
					}
dvander@1349
   988
					/* Mark as changed */
dvander@1349
   989
					pUser->serialchange++;
dvander@404
   990
					/* Break now, duplicates aren't allowed */
dvander@404
   991
					break;
dvander@404
   992
				}
dvander@404
   993
			}
dvander@404
   994
		}
dvander@404
   995
		idx = pUser->next_user;
dvander@404
   996
	}
dvander@335
   997
}
dvander@335
   998
dvander@335
   999
void AdminCache::InvalidateGroupCache()
dvander@335
  1000
{
dvander@335
  1001
	/* Nuke the free list */
dvander@335
  1002
	m_FreeGroupList = -1;
dvander@335
  1003
dvander@335
  1004
	/* Nuke reverse lookups */
dvander@335
  1005
	sm_trie_clear(m_pGroups);
dvander@335
  1006
dvander@335
  1007
	/* Free memory on groups */
dvander@335
  1008
	GroupId cur = m_FirstGroup;
dvander@335
  1009
	AdminGroup *pGroup;
dvander@335
  1010
	while (cur != INVALID_GROUP_ID)
dvander@335
  1011
	{
dvander@335
  1012
		pGroup = (AdminGroup *)m_pMemory->GetAddress(cur);
dvander@335
  1013
		assert(pGroup->magic == GRP_MAGIC_SET);
dvander@335
  1014
		if (pGroup->pCmdGrpTable)
dvander@335
  1015
		{
dvander@335
  1016
			sm_trie_destroy(pGroup->pCmdGrpTable);
dvander@335
  1017
		}
dvander@335
  1018
		if (pGroup->pCmdTable)
dvander@335
  1019
		{
dvander@335
  1020
			sm_trie_destroy(pGroup->pCmdTable);
dvander@335
  1021
		}
dvander@335
  1022
		cur = pGroup->next_grp;
dvander@335
  1023
	}
dvander@335
  1024
dvander@335
  1025
	m_FirstGroup = INVALID_GROUP_ID;
dvander@335
  1026
	m_LastGroup = INVALID_GROUP_ID;
dvander@335
  1027
dvander@404
  1028
	InvalidateAdminCache(false);
dvander@335
  1029
dvander@335
  1030
	/* Reset the memory table */
dvander@335
  1031
	m_pMemory->Reset();
dvander@335
  1032
}
dvander@336
  1033
dvander@336
  1034
void AdminCache::AddAdminListener(IAdminListener *pListener)
dvander@336
  1035
{
dvander@336
  1036
	m_hooks.push_back(pListener);
dvander@336
  1037
}
dvander@336
  1038
dvander@336
  1039
void AdminCache::RemoveAdminListener(IAdminListener *pListener)
dvander@336
  1040
{
dvander@336
  1041
	m_hooks.remove(pListener);
dvander@336
  1042
}
dvander@336
  1043
dvander@404
  1044
void AdminCache::RegisterAuthIdentType(const char *name)
dvander@404
  1045
{
dvander@404
  1046
	if (sm_trie_retrieve(m_pAuthTables, name, NULL))
dvander@404
  1047
	{
dvander@404
  1048
		return;
dvander@404
  1049
	}
dvander@404
  1050
dvander@404
  1051
	Trie *pAuth = sm_trie_create();
dvander@404
  1052
dvander@404
  1053
	AuthMethod method;
dvander@404
  1054
	method.name.assign(name);
dvander@404
  1055
	method.table = pAuth;
dvander@404
  1056
dvander@404
  1057
	m_AuthMethods.push_back(method);
dvander@404
  1058
dvander@404
  1059
	sm_trie_insert(m_pAuthTables, name, pAuth);
dvander@404
  1060
}
dvander@404
  1061
dvander@404
  1062
void AdminCache::InvalidateAdminCache(bool unlink_admins)
dvander@404
  1063
{
dvander@458
  1064
	m_InvalidatingAdmins = true;
dvander@520
  1065
	if (!m_destroying)
dvander@520
  1066
	{
dvander@520
  1067
		g_Players.ClearAllAdmins();
dvander@520
  1068
	}
dvander@404
  1069
	/* Wipe the identity cache first */
dvander@404
  1070
	List<AuthMethod>::iterator iter;
dvander@404
  1071
	for (iter=m_AuthMethods.begin();
dvander@404
  1072
		 iter!=m_AuthMethods.end();
dvander@404
  1073
		 iter++)
dvander@404
  1074
	{
dvander@404
  1075
		sm_trie_clear((*iter).table);
dvander@404
  1076
	}
dvander@404
  1077
	
dvander@405
  1078
	if (unlink_admins)
dvander@404
  1079
	{
dvander@405
  1080
		while (m_FirstUser != INVALID_ADMIN_ID)
dvander@405
  1081
		{
dvander@405
  1082
			InvalidateAdmin(m_FirstUser);
dvander@405
  1083
		}
dvander@405
  1084
	} else {
dvander@405
  1085
		m_FirstUser = -1;
dvander@405
  1086
		m_LastUser = -1;
dvander@405
  1087
		m_FreeUserList = -1;
dvander@404
  1088
	}
dvander@458
  1089
	m_InvalidatingAdmins = false;
dvander@404
  1090
}
dvander@404
  1091
dvander@438
  1092
void AdminCache::DumpAdminCache(AdminCachePart part, bool rebuild)
dvander@336
  1093
{
dvander@438
  1094
	List<IAdminListener *>::iterator iter;
dvander@438
  1095
	IAdminListener *pListener;
dvander@438
  1096
	cell_t result;
dvander@438
  1097
dvander@438
  1098
	if (part == AdminCache_Overrides)
dvander@336
  1099
	{
dvander@336
  1100
		DumpCommandOverrideCache(Override_Command);
dvander@336
  1101
		DumpCommandOverrideCache(Override_CommandGroup);
dvander@520
  1102
		if (rebuild && !m_destroying)
dvander@438
  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->OnRebuildOverrideCache();
dvander@438
  1108
			}
dvander@438
  1109
			m_pCacheFwd->PushCell(part);
dvander@438
  1110
			m_pCacheFwd->Execute(&result);
dvander@438
  1111
		}
dvander@438
  1112
	} else if (part == AdminCache_Groups || part == AdminCache_Admins) {
dvander@438
  1113
		if (part == AdminCache_Groups)
dvander@438
  1114
		{
dvander@438
  1115
			InvalidateGroupCache();
dvander@520
  1116
			if (rebuild && !m_destroying)
dvander@438
  1117
			{
dvander@438
  1118
				for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
dvander@438
  1119
				{
dvander@438
  1120
					pListener = (*iter);
dvander@438
  1121
					pListener->OnRebuildGroupCache();
dvander@438
  1122
				}
dvander@438
  1123
				m_pCacheFwd->PushCell(part);
dvander@438
  1124
				m_pCacheFwd->Execute(&result);
dvander@438
  1125
			}
dvander@438
  1126
		}
dvander@404
  1127
		InvalidateAdminCache(true);
dvander@520
  1128
		if (rebuild && !m_destroying)
dvander@336
  1129
		{
dvander@438
  1130
			for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
dvander@438
  1131
			{
dvander@438
  1132
				pListener = (*iter);
dvander@438
  1133
				pListener->OnRebuildAdminCache((part == AdminCache_Groups));
dvander@438
  1134
			}
dvander@438
  1135
			m_pCacheFwd->PushCell(AdminCache_Admins);
dvander@438
  1136
			m_pCacheFwd->Execute(&result);
dvander@1165
  1137
			g_Players.RecheckAnyAdmins();
dvander@336
  1138
		}
dvander@336
  1139
	}
dvander@336
  1140
}
dvander@404
  1141
dvander@404
  1142
const char *AdminCache::GetAdminName(AdminId id)
dvander@404
  1143
{
dvander@404
  1144
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@404
  1145
	if (!pUser || pUser->magic != USR_MAGIC_SET)
dvander@404
  1146
	{
dvander@404
  1147
		return NULL;
dvander@404
  1148
	}
dvander@404
  1149
dvander@404
  1150
	return m_pStrings->GetString(pUser->nameidx);
dvander@404
  1151
}
dvander@404
  1152
dvander@405
  1153
bool AdminCache::GetMethodIndex(const char *name, unsigned int *_index)
dvander@405
  1154
{
dvander@405
  1155
	List<AuthMethod>::iterator iter;
dvander@405
  1156
	unsigned int index = 0;
dvander@405
  1157
	for (iter=m_AuthMethods.begin();
dvander@405
  1158
		 iter!=m_AuthMethods.end();
dvander@405
  1159
		 iter++,index++)
dvander@405
  1160
	{
dvander@405
  1161
		if ((*iter).name.compare(name) == 0)
dvander@405
  1162
		{
dvander@405
  1163
			*_index = index;
dvander@405
  1164
			return true;
dvander@405
  1165
		}
dvander@405
  1166
	}
dvander@405
  1167
dvander@405
  1168
	return false;
dvander@405
  1169
}
dvander@405
  1170
dvander@404
  1171
bool AdminCache::BindAdminIdentity(AdminId id, const char *auth, const char *ident)
dvander@404
  1172
{
rbutler14@2491
  1173
	if (ident[0] == '\0')
rbutler14@2490
  1174
	{
rbutler14@2490
  1175
		return false;
rbutler14@2490
  1176
	}
rbutler14@2490
  1177
dvander@404
  1178
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@404
  1179
	if (!pUser || pUser->magic != USR_MAGIC_SET)
dvander@404
  1180
	{
dvander@404
  1181
		return false;
dvander@404
  1182
	}
dvander@404
  1183
dvander@404
  1184
	Trie *pTable;
dvander@404
  1185
	if (!sm_trie_retrieve(m_pAuthTables, auth, (void **)&pTable))
dvander@404
  1186
	{
dvander@404
  1187
		return false;
dvander@404
  1188
	}
dvander@404
  1189
pred@2420
  1190
	/* If the id was a steam id strip off the STEAM_*: part */
pred@2420
  1191
	if (strcmp(auth, "steam") == 0 && strncmp(ident, "STEAM_", 6) == 0)
pred@2420
  1192
	{
pred@2420
  1193
		ident += 8;
pred@2420
  1194
	}
pred@2420
  1195
dvander@404
  1196
	if (sm_trie_retrieve(pTable, ident, NULL))
dvander@404
  1197
	{
dvander@404
  1198
		return false;
dvander@404
  1199
	}
dvander@404
  1200
dvander@1356
  1201
	int i_ident = m_pStrings->AddString(ident);
dvander@1356
  1202
dvander@1356
  1203
	pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@1356
  1204
	pUser->auth.identidx = i_ident;
dvander@405
  1205
	GetMethodIndex(auth, &pUser->auth.index);
dvander@405
  1206
dvander@404
  1207
	return sm_trie_insert(pTable, ident, (void **)id);
dvander@404
  1208
}
dvander@404
  1209
dvander@404
  1210
AdminId AdminCache::FindAdminByIdentity(const char *auth, const char *identity)
dvander@404
  1211
{
dvander@404
  1212
	Trie *pTable;
dvander@404
  1213
	if (!sm_trie_retrieve(m_pAuthTables, auth, (void **)&pTable))
dvander@404
  1214
	{
dvander@404
  1215
		return INVALID_ADMIN_ID;
dvander@404
  1216
	}
dvander@404
  1217
pred@2420
  1218
	/* If the id was a steam id strip off the STEAM_*: part */
pred@2420
  1219
	if (strcmp(auth, "steam") == 0 && strncmp(identity, "STEAM_", 6) == 0)
pred@2420
  1220
	{
pred@2420
  1221
		identity += 8;
pred@2420
  1222
	}
pred@2420
  1223
dvander@404
  1224
	void *object;
dvander@404
  1225
	if (!sm_trie_retrieve(pTable, identity, &object))
dvander@404
  1226
	{
dvander@404
  1227
		return INVALID_ADMIN_ID;
dvander@404
  1228
	}
dvander@404
  1229
dvander@404
  1230
	return (AdminId)object;
dvander@404
  1231
}
dvander@404
  1232
dvander@404
  1233
void AdminCache::SetAdminFlag(AdminId id, AdminFlag flag, bool enabled)
dvander@404
  1234
{
dvander@404
  1235
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@404
  1236
	if (!pUser || pUser->magic != USR_MAGIC_SET)
dvander@404
  1237
	{
dvander@404
  1238
		return;
dvander@404
  1239
	}
dvander@404
  1240
dvander@433
  1241
	if (flag < Admin_Reservation
dvander@404
  1242
		|| flag >= AdminFlags_TOTAL)
dvander@404
  1243
	{
dvander@404
  1244
		return;
dvander@404
  1245
	}
dvander@436
  1246
	
dvander@436
  1247
	FlagBits bits = (1<<(FlagBits)flag);
dvander@404
  1248
dvander@436
  1249
	if (enabled)
dvander@436
  1250
	{
dvander@436
  1251
		pUser->flags |= bits;
dvander@436
  1252
		pUser->eflags |= bits;
dvander@436
  1253
	} else {
dvander@436
  1254
		pUser->flags &= ~bits;
dvander@436
  1255
		pUser->eflags &= ~bits;
dvander@436
  1256
	}
dvander@1349
  1257
dvander@1349
  1258
	pUser->serialchange++;
dvander@404
  1259
}
dvander@404
  1260
dvander@404
  1261
bool AdminCache::GetAdminFlag(AdminId id, AdminFlag flag, AccessMode mode)
dvander@404
  1262
{
dvander@404
  1263
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@404
  1264
	if (!pUser || pUser->magic != USR_MAGIC_SET)
dvander@404
  1265
	{
dvander@404
  1266
		return false;
dvander@404
  1267
	}
dvander@404
  1268
dvander@433
  1269
	if (flag < Admin_Reservation
dvander@404
  1270
		|| flag >= AdminFlags_TOTAL)
dvander@404
  1271
	{
dvander@404
  1272
		return false;
dvander@404
  1273
	}
dvander@404
  1274
dvander@433
  1275
	FlagBits bit = (1<<(FlagBits)flag);
dvander@433
  1276
dvander@404
  1277
	if (mode == Access_Real)
dvander@404
  1278
	{
dvander@433
  1279
		return ((pUser->flags & bit) == bit);
dvander@404
  1280
	} else if (mode == Access_Effective) {
dvander@907
  1281
		bool has_bit = ((pUser->eflags & bit) == bit);
dvander@907
  1282
		if (!has_bit && flag != Admin_Root && ((pUser->eflags & ADMFLAG_ROOT) == ADMFLAG_ROOT))
dvander@907
  1283
		{
dvander@907
  1284
			has_bit = true;
dvander@907
  1285
		}
dvander@907
  1286
		return has_bit;
dvander@404
  1287
	}
dvander@404
  1288
dvander@404
  1289
	return false;
dvander@404
  1290
}
dvander@404
  1291
dvander@433
  1292
FlagBits AdminCache::GetAdminFlags(AdminId id, AccessMode mode)
dvander@404
  1293
{
dvander@404
  1294
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@404
  1295
	if (!pUser || pUser->magic != USR_MAGIC_SET)
dvander@404
  1296
	{
dvander@404
  1297
		return 0;
dvander@404
  1298
	}
dvander@404
  1299
dvander@404
  1300
	if (mode == Access_Real)
dvander@404
  1301
	{
dvander@433
  1302
		return pUser->flags;
dvander@404
  1303
	} else if (mode == Access_Effective) {
dvander@433
  1304
		return pUser->eflags;
dvander@404
  1305
	}
dvander@404
  1306
dvander@433
  1307
	return 0;
dvander@404
  1308
}
dvander@404
  1309
dvander@458
  1310
void AdminCache::SetAdminFlags(AdminId id, AccessMode mode, FlagBits bits)
dvander@458
  1311
{
dvander@458
  1312
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@458
  1313
	if (!pUser || pUser->magic != USR_MAGIC_SET)
dvander@458
  1314
	{
dvander@458
  1315
		return;
dvander@458
  1316
	}
dvander@458
  1317
dvander@458
  1318
	if (mode == Access_Real)
dvander@458
  1319
	{
dvander@458
  1320
		pUser->flags = bits;
dvander@458
  1321
		pUser->eflags = bits;
dvander@458
  1322
	} else if (mode == Access_Effective) {
dvander@458
  1323
		pUser->eflags = bits;
dvander@458
  1324
	}
dvander@1349
  1325
dvander@1349
  1326
	pUser->serialchange++;
dvander@458
  1327
}
dvander@458
  1328
dvander@404
  1329
bool AdminCache::AdminInheritGroup(AdminId id, GroupId gid)
dvander@404
  1330
{
dvander@404
  1331
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@404
  1332
	if (!pUser || pUser->magic != USR_MAGIC_SET)
dvander@404
  1333
	{
dvander@404
  1334
		return false;
dvander@404
  1335
	}
dvander@404
  1336
dvander@404
  1337
	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(gid);
dvander@405
  1338
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@404
  1339
	{
dvander@404
  1340
		return false;
dvander@404
  1341
	}
dvander@404
  1342
dvander@433
  1343
	/* First check for duplicates */
dvander@433
  1344
	if (pUser->grp_count != 0)
dvander@433
  1345
	{
dvander@433
  1346
		int *temp_table = (int *)m_pMemory->GetAddress(pUser->grp_table);
dvander@433
  1347
		for (unsigned int i=0; i<pUser->grp_count; i++)
dvander@433
  1348
		{
dvander@433
  1349
			if (temp_table[i] == gid)
dvander@433
  1350
			{
dvander@433
  1351
				return false;
dvander@433
  1352
			}
dvander@433
  1353
		}
dvander@433
  1354
	}
dvander@433
  1355
dvander@404
  1356
	int *table;
dvander@404
  1357
	if (pUser->grp_count + 1 > pUser->grp_size)
dvander@404
  1358
	{
dvander@404
  1359
		int new_size = 0;
dvander@404
  1360
		int tblidx;
dvander@404
  1361
		
dvander@404
  1362
		if (pUser->grp_size == 0)
dvander@404
  1363
		{
dvander@404
  1364
			new_size = 2;
dvander@404
  1365
		} else {
dvander@404
  1366
			new_size = pUser->grp_size * 2;
dvander@404
  1367
		}
dvander@404
  1368
		
dvander@404
  1369
		/* Create and refresh pointers */
dvander@404
  1370
		tblidx = m_pMemory->CreateMem(new_size * sizeof(int), (void **)&table);
dvander@404
  1371
		pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@404
  1372
		pGroup = (AdminGroup *)m_pMemory->GetAddress(gid);
dvander@404
  1373
dvander@404
  1374
		/* Copy old data if necessary */
dvander@404
  1375
		if (pUser->grp_table != -1)
dvander@404
  1376
		{
dvander@404
  1377
			int *old_table = (int *)m_pMemory->GetAddress(pUser->grp_table);
dvander@404
  1378
			memcpy(table, old_table, sizeof(int) * pUser->grp_count);
dvander@404
  1379
		}
dvander@404
  1380
		pUser->grp_table = tblidx;
dvander@404
  1381
		pUser->grp_size = new_size;
dvander@404
  1382
	} else {
dvander@404
  1383
		table = (int *)m_pMemory->GetAddress(pUser->grp_table);
dvander@404
  1384
	}
dvander@404
  1385
dvander@404
  1386
	table[pUser->grp_count] = gid;
dvander@404
  1387
	pUser->grp_count++;
dvander@404
  1388
dvander@434
  1389
	/* Compute new effective permissions */
dvander@433
  1390
	pUser->eflags |= pGroup->addflags;
dvander@404
  1391
dvander@1403
  1392
	if (pGroup->immunity_level > pUser->immunity_level)
dvander@434
  1393
	{
dvander@1403
  1394
		pUser->immunity_level = pGroup->immunity_level;
dvander@434
  1395
	}
dvander@434
  1396
dvander@1349
  1397
	pUser->serialchange++;
dvander@1349
  1398
dvander@404
  1399
	return true;
dvander@404
  1400
}
dvander@404
  1401
dvander@458
  1402
bool AdminCache::IsValidAdmin(AdminId id)
dvander@458
  1403
{
dvander@458
  1404
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@458
  1405
	return (pUser != NULL && pUser->magic == USR_MAGIC_SET);
dvander@458
  1406
}
dvander@458
  1407
dvander@404
  1408
unsigned int AdminCache::GetAdminGroupCount(AdminId id)
dvander@404
  1409
{
dvander@404
  1410
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@404
  1411
	if (!pUser || pUser->magic != USR_MAGIC_SET)
dvander@404
  1412
	{
dvander@404
  1413
		return 0;
dvander@404
  1414
	}
dvander@404
  1415
dvander@404
  1416
	return pUser->grp_count;
dvander@404
  1417
}
dvander@404
  1418
dvander@404
  1419
GroupId AdminCache::GetAdminGroup(AdminId id, unsigned int index, const char **name)
dvander@404
  1420
{
dvander@404
  1421
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@404
  1422
	if (!pUser || pUser->magic != USR_MAGIC_SET || index >= pUser->grp_count)
dvander@404
  1423
	{
dvander@404
  1424
		return INVALID_GROUP_ID;
dvander@404
  1425
	}
dvander@404
  1426
dvander@404
  1427
	int *table = (int *)m_pMemory->GetAddress(pUser->grp_table);
dvander@404
  1428
dvander@1356
  1429
	GroupId gid = table[index];
dvander@1356
  1430
dvander@1356
  1431
	if (name)
dvander@1356
  1432
	{
dvander@1356
  1433
		*name = GetGroupName(gid);
dvander@1356
  1434
	}
dvander@1356
  1435
dvander@1356
  1436
	return gid;
dvander@404
  1437
}
dvander@404
  1438
dvander@404
  1439
const char *AdminCache::GetAdminPassword(AdminId id)
dvander@404
  1440
{
dvander@404
  1441
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@404
  1442
	if (!pUser || pUser->magic != USR_MAGIC_SET)
dvander@404
  1443
	{
dvander@404
  1444
		return NULL;
dvander@404
  1445
	}
dvander@404
  1446
dvander@404
  1447
	return m_pStrings->GetString(pUser->password);
dvander@404
  1448
}
dvander@404
  1449
dvander@404
  1450
void AdminCache::SetAdminPassword(AdminId id, const char *password)
dvander@404
  1451
{	
dvander@404
  1452
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@404
  1453
	if (!pUser || pUser->magic != USR_MAGIC_SET)
dvander@404
  1454
	{
dvander@404
  1455
		return;
dvander@404
  1456
	}
dvander@404
  1457
dvander@2073
  1458
	if (password[0] == '\0')
dvander@2073
  1459
	{
dvander@2073
  1460
		pUser->password = -1;
dvander@2073
  1461
		return;
dvander@2073
  1462
	}
dvander@2073
  1463
dvander@1356
  1464
	int i_password = m_pStrings->AddString(password);
dvander@1356
  1465
	pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@1356
  1466
	pUser->password = i_password;
dvander@404
  1467
}
dvander@404
  1468
dvander@433
  1469
unsigned int AdminCache::FlagBitsToBitArray(FlagBits bits, bool array[], unsigned int maxSize)
dvander@433
  1470
{
dvander@433
  1471
	unsigned int i;
dvander@433
  1472
	for (i=0; i<maxSize && i<AdminFlags_TOTAL; i++)
dvander@433
  1473
	{
dvander@464
  1474
		array[i] = ((bits & (1<<i)) == (unsigned)(1<<i));
dvander@433
  1475
	}
dvander@433
  1476
dvander@433
  1477
	return i;
dvander@433
  1478
}
dvander@433
  1479
dvander@433
  1480
FlagBits AdminCache::FlagBitArrayToBits(const bool array[], unsigned int maxSize)
dvander@433
  1481
{
dvander@433
  1482
	FlagBits bits = 0;
dvander@433
  1483
	for (unsigned int i=0; i<maxSize && i<AdminFlags_TOTAL; i++)
dvander@433
  1484
	{
dvander@433
  1485
		if (array[i])
dvander@433
  1486
		{
dvander@433
  1487
			bits |= (1<<i);
dvander@433
  1488
		}
dvander@433
  1489
	}
dvander@433
  1490
dvander@433
  1491
	return bits;
dvander@433
  1492
}
dvander@433
  1493
dvander@433
  1494
FlagBits AdminCache::FlagArrayToBits(const AdminFlag array[], unsigned int numFlags)
dvander@433
  1495
{
dvander@433
  1496
	FlagBits bits = 0;
dvander@433
  1497
	for (unsigned int i=0; i<numFlags && i<AdminFlags_TOTAL; i++)
dvander@433
  1498
	{
dvander@433
  1499
		bits |= (1 << (FlagBits)array[i]);
dvander@433
  1500
	}
dvander@433
  1501
dvander@433
  1502
	return bits;
dvander@433
  1503
}
dvander@433
  1504
dvander@433
  1505
unsigned int AdminCache::FlagBitsToArray(FlagBits bits, AdminFlag array[], unsigned int maxSize)
dvander@433
  1506
{
dvander@433
  1507
	unsigned int i, num=0;
dvander@1050
  1508
	for (i=0; num<maxSize && i<AdminFlags_TOTAL; i++)
dvander@433
  1509
	{
dvander@464
  1510
		if ((bits & (1<<i)) == (unsigned)(1<<i))
dvander@433
  1511
		{
dvander@433
  1512
			array[num++] = (AdminFlag)i;
dvander@433
  1513
		}
dvander@433
  1514
	}
dvander@433
  1515
dvander@433
  1516
	return num;
dvander@433
  1517
}
dvander@434
  1518
dvander@434
  1519
bool AdminCache::CheckAdminFlags(AdminId id, FlagBits bits)
dvander@434
  1520
{
dvander@434
  1521
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@434
  1522
	if (!pUser || pUser->magic != USR_MAGIC_SET)
dvander@434
  1523
	{
dvander@434
  1524
		return false;
dvander@434
  1525
	}
dvander@434
  1526
dvander@434
  1527
	return ((pUser->eflags & bits) == bits);
dvander@434
  1528
}
dvander@434
  1529
dvander@434
  1530
bool AdminCache::CanAdminTarget(AdminId id, AdminId target)
dvander@434
  1531
{
dvander@434
  1532
	/** 
dvander@434
  1533
	 * Zeroth, if the targeting AdminId is INVALID_ADMIN_ID, targeting fails.
ds@729
  1534
	 * First, if the targeted AdminId is INVALID_ADMIN_ID, targeting succeeds.
dvander@434
  1535
	 */
dvander@434
  1536
dvander@434
  1537
	if (id == INVALID_ADMIN_ID)
dvander@434
  1538
	{
dvander@434
  1539
		return false;
dvander@434
  1540
	}
dvander@434
  1541
dvander@434
  1542
	if (target == INVALID_ADMIN_ID)
dvander@434
  1543
	{
dvander@434
  1544
		return true;
dvander@434
  1545
	}
dvander@434
  1546
dvander@1403
  1547
	if (id == target)
dvander@1403
  1548
	{
dvander@1403
  1549
		return true;
dvander@1403
  1550
	}
dvander@1403
  1551
dvander@434
  1552
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@434
  1553
	if (!pUser || pUser->magic != USR_MAGIC_SET)
dvander@434
  1554
	{
dvander@434
  1555
		return false;
dvander@434
  1556
	}
dvander@434
  1557
dvander@434
  1558
	AdminUser *pTarget = (AdminUser *)m_pMemory->GetAddress(target);
dvander@434
  1559
	if (!pTarget || pTarget->magic != USR_MAGIC_SET)
dvander@434
  1560
	{
dvander@434
  1561
		return false;
dvander@434
  1562
	}
dvander@434
  1563
dvander@434
  1564
	/** 
ds@729
  1565
	 * Second, if the targeting admin is root, targeting succeeds.
dvander@434
  1566
	 */
dvander@434
  1567
	if (pUser->eflags & ADMFLAG_ROOT)
dvander@434
  1568
	{
dvander@434
  1569
		return true;
dvander@434
  1570
	}
dvander@434
  1571
dvander@1403
  1572
	/** Fourth, if the targeted admin is immune from targeting admin. */
dvander@1403
  1573
	int mode = sm_immunity_mode.GetInt();
dvander@1403
  1574
	switch (mode)
dvander@434
  1575
	{
dvander@1403
  1576
		case 1:
dvander@1403
  1577
		{
dvander@1403
  1578
			if (pTarget->immunity_level > pUser->immunity_level)
dvander@1403
  1579
			{
dvander@1403
  1580
				return false;
dvander@1403
  1581
			}
dvander@1403
  1582
			break;
dvander@1403
  1583
		}
dvander@1403
  1584
		case 3:
dvander@1403
  1585
		{
dvander@1403
  1586
			/* If neither has any immunity, let this pass. */
dvander@1403
  1587
			if (!pUser->immunity_level && !pTarget->immunity_level)
dvander@1403
  1588
			{
dvander@1403
  1589
				return true;
dvander@1403
  1590
			}
dvander@1403
  1591
			/* Don't break, go to the next case. */
dvander@1403
  1592
		}
dvander@1403
  1593
		case 2:
dvander@1403
  1594
		{
dvander@1403
  1595
			if (pTarget->immunity_level >= pUser->immunity_level)
dvander@1403
  1596
			{
dvander@1403
  1597
				return false;
dvander@1403
  1598
			}
dvander@1403
  1599
			break;
dvander@1403
  1600
		}
dvander@434
  1601
	}
dvander@434
  1602
dvander@434
  1603
	/** 
dvander@1403
  1604
	 * Fifth, if the targeted admin has specific immunity from the
dvander@434
  1605
	 *  targeting admin via group immunities, targeting fails.
dvander@434
  1606
	 */
dvander@434
  1607
	//:TODO: speed this up... maybe with trie hacks.
dvander@434
  1608
	//idea is to insert %d.%d in the trie after computing this and use it as a cache lookup.
dvander@434
  1609
	//problem is the trie cannot delete prefixes, so we'd have a problem with invalidations.
dvander@434
  1610
	if (pTarget->grp_count > 0 && pUser->grp_count > 0)
dvander@434
  1611
	{
dvander@434
  1612
		int *grp_table = (int *)m_pMemory->GetAddress(pTarget->grp_table);
dvander@434
  1613
		int *src_table = (int *)m_pMemory->GetAddress(pUser->grp_table);
dvander@434
  1614
		GroupId id, other;
dvander@434
  1615
		unsigned int num;
dvander@434
  1616
		for (unsigned int i=0; i<pTarget->grp_count; i++)
dvander@434
  1617
		{
dvander@434
  1618
			id = grp_table[i];
dvander@434
  1619
			num = GetGroupImmunityCount(id);
dvander@434
  1620
			for (unsigned int j=0; j<num; i++)
dvander@434
  1621
			{
dvander@434
  1622
				other = GetGroupImmunity(id, j);
dvander@434
  1623
				for (unsigned int k=0; k<pUser->grp_count; k++)
dvander@434
  1624
				{
dvander@434
  1625
					if (other == src_table[k])
dvander@434
  1626
					{
dvander@434
  1627
						return false;
dvander@434
  1628
					}
dvander@434
  1629
				}
dvander@434
  1630
			}
dvander@434
  1631
		}
dvander@434
  1632
	}
dvander@434
  1633
	
dvander@434
  1634
	return true;
dvander@434
  1635
}
dvander@1298
  1636
dvander@1298
  1637
bool AdminCache::FindFlag(char c, AdminFlag *pAdmFlag)
dvander@1298
  1638
{
dvander@1965
  1639
	if (c < 'a' 
dvander@1965
  1640
		|| c > 'z'
dvander@1965
  1641
		|| !g_FlagSet[(unsigned)c - (unsigned)'a'])
dvander@1298
  1642
	{
dvander@1298
  1643
		return false;
dvander@1298
  1644
	}
dvander@1298
  1645
dvander@1305
  1646
	if (pAdmFlag)
dvander@1298
  1647
	{
dvander@1298
  1648
		*pAdmFlag = g_FlagLetters[(unsigned)c - (unsigned)'a'];
dvander@1298
  1649
	}
dvander@1298
  1650
dvander@1298
  1651
	return true;
dvander@1298
  1652
}
dvander@1298
  1653
dvander@1965
  1654
bool AdminCache::FindFlagChar(AdminFlag flag, char *c)
dvander@1965
  1655
{
dvander@1965
  1656
	if (!g_FlagSet[flag])
dvander@1965
  1657
	{
dvander@1965
  1658
		return false;
dvander@1965
  1659
	}
dvander@1965
  1660
dvander@1965
  1661
	if (c)
dvander@1965
  1662
	{
dvander@1965
  1663
		*c = g_ReverseFlags[flag];
dvander@1965
  1664
	}
dvander@1965
  1665
dvander@1965
  1666
	return true;
dvander@1965
  1667
}
dvander@1965
  1668
dvander@1298
  1669
FlagBits AdminCache::ReadFlagString(const char *flags, const char **end)
dvander@1298
  1670
{
dvander@1298
  1671
	FlagBits bits = 0;
dvander@1298
  1672
dvander@1298
  1673
	while (flags && (*flags != '\0'))
dvander@1298
  1674
	{
dvander@1298
  1675
		AdminFlag flag;
dvander@1298
  1676
		if (!FindFlag(*flags, &flag))
dvander@1298
  1677
		{
dvander@1298
  1678
			break;
dvander@1298
  1679
		}
dvander@1298
  1680
		bits |= FlagArrayToBits(&flag, 1);
dvander@1298
  1681
		flags++;
dvander@1298
  1682
	}
dvander@1298
  1683
dvander@1298
  1684
	if (end)
dvander@1298
  1685
	{
dvander@1298
  1686
		*end = flags;
dvander@1298
  1687
	}
dvander@1298
  1688
dvander@1298
  1689
	return bits;
dvander@1298
  1690
}
dvander@1349
  1691
dvander@1349
  1692
unsigned int AdminCache::GetAdminSerialChange(AdminId id)
dvander@1349
  1693
{
dvander@1349
  1694
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@1349
  1695
	if (!pUser || pUser->magic != USR_MAGIC_SET)
dvander@1349
  1696
	{
dvander@1349
  1697
		return 0;
dvander@1349
  1698
	}
dvander@1349
  1699
dvander@1349
  1700
	return pUser->serialchange;
dvander@1349
  1701
}
dvander@1349
  1702
dvander@1349
  1703
bool AdminCache::CanAdminUseCommand(int client, const char *cmd)
dvander@1349
  1704
{
dvander@1349
  1705
	FlagBits bits;
dvander@1349
  1706
	OverrideType otype = Override_Command;
dvander@1349
  1707
dvander@1349
  1708
	if (cmd[0] == '@')
dvander@1349
  1709
	{
dvander@1349
  1710
		otype = Override_CommandGroup;
dvander@1349
  1711
		cmd++;
dvander@1349
  1712
	}
dvander@1349
  1713
dvander@1349
  1714
	if (!g_ConCmds.LookForCommandAdminFlags(cmd, &bits))
dvander@1349
  1715
	{
dvander@1349
  1716
		if (!GetCommandOverride(cmd, otype, &bits))
dvander@1349
  1717
		{
dvander@1349
  1718
			bits = 0;
dvander@1349
  1719
		}
dvander@1349
  1720
	}
dvander@1349
  1721
dvander@1349
  1722
	return g_ConCmds.CheckCommandAccess(client, cmd, bits);
dvander@1349
  1723
}
dvander@1403
  1724
dvander@1403
  1725
unsigned int AdminCache::SetGroupImmunityLevel(GroupId gid, unsigned int level)
dvander@1403
  1726
{
dvander@1403
  1727
	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(gid);
dvander@1403
  1728
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@1403
  1729
	{
dvander@1403
  1730
		return 0;
dvander@1403
  1731
	}
dvander@1403
  1732
dvander@1403
  1733
	unsigned int old_level = pGroup->immunity_level;
dvander@1403
  1734
dvander@1403
  1735
	pGroup->immunity_level = level;
dvander@1403
  1736
dvander@1403
  1737
	return old_level;
dvander@1403
  1738
}
dvander@1403
  1739
dvander@1403
  1740
unsigned int AdminCache::GetGroupImmunityLevel(GroupId gid)
dvander@1403
  1741
{
dvander@1403
  1742
	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(gid);
dvander@1403
  1743
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@1403
  1744
	{
dvander@1403
  1745
		return 0;
dvander@1403
  1746
	}
dvander@1403
  1747
dvander@1403
  1748
	return pGroup->immunity_level;
dvander@1403
  1749
}
dvander@1403
  1750
dvander@1403
  1751
unsigned int AdminCache::SetAdminImmunityLevel(AdminId id, unsigned int level)
dvander@1403
  1752
{
dvander@1403
  1753
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@1403
  1754
	if (!pUser || pUser->magic != USR_MAGIC_SET)
dvander@1403
  1755
	{
dvander@1403
  1756
		return 0;
dvander@1403
  1757
	}
dvander@1403
  1758
dvander@1403
  1759
	unsigned int old_level = pUser->immunity_level;
dvander@1403
  1760
dvander@1403
  1761
	pUser->immunity_level = level;
dvander@1403
  1762
dvander@1403
  1763
	return old_level;
dvander@1403
  1764
}
dvander@1403
  1765
dvander@1403
  1766
unsigned int AdminCache::GetAdminImmunityLevel(AdminId id)
dvander@1403
  1767
{
dvander@1403
  1768
	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
dvander@1403
  1769
	if (!pUser || pUser->magic != USR_MAGIC_SET)
dvander@1403
  1770
	{
dvander@1403
  1771
		return 0;
dvander@1403
  1772
	}
dvander@1403
  1773
dvander@1403
  1774
	return pUser->immunity_level;
dvander@1403
  1775
}
dvander@1403
  1776
dvander@1477
  1777
bool AdminCache::CheckAccess(int client, const char *cmd, FlagBits flags, bool override_only)
dvander@1473
  1778
{
dvander@1473
  1779
	if (client == 0)
dvander@1473
  1780
	{
dvander@1473
  1781
		return true;
dvander@1473
  1782
	}
dvander@1473
  1783
dvander@1473
  1784
	/* Auto-detect a command if we can */
dvander@1473
  1785
	FlagBits bits = flags;
dvander@1473
  1786
	bool found_command = false;
dvander@1473
  1787
	if (!override_only)
dvander@1473
  1788
	{
dvander@1473
  1789
		found_command = g_ConCmds.LookForCommandAdminFlags(cmd, &bits);
dvander@1473
  1790
	}
dvander@1473
  1791
dvander@1473
  1792
	if (!found_command)
dvander@1473
  1793
	{
dvander@1473
  1794
		GetCommandOverride(cmd, Override_Command, &bits);
dvander@1473
  1795
	}
dvander@1473
  1796
dvander@1473
  1797
	return g_ConCmds.CheckCommandAccess(client, cmd, bits) ? 1 : 0;
dvander@1473
  1798
}
dvander@1965
  1799
dvander@1965
  1800
void iterator_glob_basic_override(Trie *pTrie, const char *key, void **value, void *data)
dvander@1965
  1801
{
dvander@1965
  1802
	FILE *fp;
dvander@1965
  1803
	int flags;
dvander@1965
  1804
	char flagstr[64];
dvander@1965
  1805
dvander@1965
  1806
	fp = (FILE *)data;
dvander@1965
  1807
	flags = (int)*value;
dvander@1965
  1808
	g_Admins.FillFlagString(flags, flagstr, sizeof(flagstr));
dvander@1965
  1809
dvander@1965
  1810
	fprintf(fp, "\t\"%s\"\t\t\"%s\"\n", key, flagstr);
dvander@1965
  1811
}
dvander@1965
  1812
dvander@1965
  1813
void iterator_glob_grp_override(Trie *pTrie, const char *key, void **value, void *data)
dvander@1965
  1814
{
dvander@1965
  1815
	FILE *fp;
dvander@1965
  1816
	int flags;
dvander@1965
  1817
	char flagstr[64];
dvander@1965
  1818
dvander@1965
  1819
	fp = (FILE *)data;
dvander@1965
  1820
	flags = (int)*value;
dvander@1965
  1821
	g_Admins.FillFlagString(flags, flagstr, sizeof(flagstr));
dvander@1965
  1822
dvander@1965
  1823
	fprintf(fp, "\t\"@%s\"\t\t\"%s\"\n", key, flagstr);
dvander@1965
  1824
}
dvander@1965
  1825
dvander@1965
  1826
void iterator_group_basic_override(Trie *pTrie, const char *key, void **value, void *data)
dvander@1965
  1827
{
dvander@1965
  1828
	FILE *fp;
dvander@1965
  1829
	int flags;
dvander@1965
  1830
	char flagstr[64];
dvander@1965
  1831
dvander@1965
  1832
	fp = (FILE *)data;
dvander@1965
  1833
	flags = (int)*value;
dvander@1965
  1834
	g_Admins.FillFlagString(flags, flagstr, sizeof(flagstr));
dvander@1965
  1835
dvander@1965
  1836
	fprintf(fp, "\t\t\t\"%s\"\t\t\"%s\"\n", key, flagstr);
dvander@1965
  1837
}
dvander@1965
  1838
dvander@1965
  1839
void iterator_group_grp_override(Trie *pTrie, const char *key, void **value, void *data)
dvander@1965
  1840
{
dvander@1965
  1841
	FILE *fp;
dvander@1965
  1842
	int flags;
dvander@1965
  1843
	char flagstr[64];
dvander@1965
  1844
dvander@1965
  1845
	fp = (FILE *)data;
dvander@1965
  1846
	flags = (int)*value;
dvander@1965
  1847
	g_Admins.FillFlagString(flags, flagstr, sizeof(flagstr));
dvander@1965
  1848
dvander@1965
  1849
	fprintf(fp, "\t\t\t\"@%s\"\t\t\"%s\"\n", key, flagstr);
dvander@1965
  1850
}
dvander@1965
  1851
dvander@1965
  1852
void AdminCache::DumpCache(FILE *fp)
dvander@1965
  1853
{
dvander@1965
  1854
	int *itable;
dvander@1965
  1855
	AdminId aid;
dvander@1965
  1856
	GroupId gid;
dvander@1965
  1857
	char flagstr[64];
dvander@1965
  1858
	unsigned int num;
dvander@1965
  1859
	AdminUser *pAdmin;
dvander@1965
  1860
	AdminGroup *pGroup;
dvander@1965
  1861
	char name_buffer[512];
dvander@1965
  1862
dvander@1965
  1863
	fprintf(fp, "\"Groups\"\n{\n");
dvander@1965
  1864
	
dvander@1965
  1865
	num = 0;
dvander@1965
  1866
	gid = m_FirstGroup;
dvander@1965
  1867
	while (gid != INVALID_GROUP_ID
dvander@1965
  1868
			&& (pGroup = GetGroup(gid)) != NULL)
dvander@1965
  1869
	{
dvander@1965
  1870
		num++;
dvander@1965
  1871
		FillFlagString(pGroup->addflags, flagstr, sizeof(flagstr));
dvander@1965
  1872
dvander@1965
  1873
		fprintf(fp, "\t/* num = %d, gid = 0x%X */\n", num, gid);
dvander@1965
  1874
		fprintf(fp, "\t\"%s\"\n\t{\n", GetString(pGroup->nameidx));
dvander@1965
  1875
		fprintf(fp, "\t\t\"flags\"\t\t\t\"%s\"\n", flagstr);
dvander@1965
  1876
		fprintf(fp, "\t\t\"immunity\"\t\t\"%d\"\n", pGroup->immunity_level);
dvander@1965
  1877
		
dvander@1965
  1878
		if (pGroup->immune_table != -1
dvander@1965
  1879
			&& (itable = (int *)m_pMemory->GetAddress(pGroup->immune_table)) != NULL)
dvander@1965
  1880
		{
dvander@1965
  1881
			AdminGroup *pAltGroup;
dvander@1965
  1882
			const char *gname, *mod;
dvander@1965
  1883
dvander@1965
  1884
			for (int i = 1; i <= itable[0]; i++)
dvander@1965
  1885
			{
dvander@1965
  1886
				if ((pAltGroup = GetGroup(itable[i])) == NULL)
dvander@1965
  1887
				{
dvander@1965
  1888
					/* Assume the rest of the table is corrupt */
dvander@1965
  1889
					break;
dvander@1965
  1890
				}
dvander@1965
  1891
				gname = GetString(pAltGroup->nameidx);
dvander@1965
  1892
				if (atoi(gname) != 0)
dvander@1965
  1893
				{
dvander@1965
  1894
					mod = "@";
dvander@1965
  1895
				}
dvander@1965
  1896
				else
dvander@1965
  1897
				{
dvander@1965
  1898
					mod = "";
dvander@1965
  1899
				}
dvander@1965
  1900
				fprintf(fp, "\t\t\"immunity\"\t\t\"%s%s\"\n", mod, gname);
dvander@1965
  1901
			}
dvander@1965
  1902
		}
dvander@1965
  1903
dvander@1965
  1904
		fprintf(fp, "\n\t\t\"Overrides\"\n\t\t{\n");
dvander@1965
  1905
		if (pGroup->pCmdGrpTable != NULL)
dvander@1965
  1906
		{
dvander@1965
  1907
			sm_trie_bad_iterator(pGroup->pCmdGrpTable, 
dvander@1965
  1908
				name_buffer,
dvander@1965
  1909
				sizeof(name_buffer),
dvander@1965
  1910
				iterator_group_grp_override,
dvander@1965
  1911
				fp);
dvander@1965
  1912
		}
dvander@1965
  1913
		if (pGroup->pCmdTable != NULL)
dvander@1965
  1914
		{
dvander@1965
  1915
			sm_trie_bad_iterator(pGroup->pCmdTable, 
dvander@1965
  1916
				name_buffer,
dvander@1965
  1917
				sizeof(name_buffer),
dvander@1965
  1918
				iterator_group_basic_override,
dvander@1965
  1919
				fp);
dvander@1965
  1920
		}
dvander@1965
  1921
		fprintf(fp, "\t\t}\n");
dvander@1965
  1922
dvander@1965
  1923
		fprintf(fp, "\t}\n");
dvander@1965
  1924
dvander@1965
  1925
		if ((gid = pGroup->next_grp) != INVALID_GROUP_ID)
dvander@1965
  1926
		{
dvander@1965
  1927
			fprintf(fp, "\n");
dvander@1965
  1928
		}
dvander@1965
  1929
	}
dvander@1965
  1930
dvander@1965
  1931
	fprintf(fp, "}\n\n");
dvander@1965
  1932
	fprintf(fp, "\"Admins\"\n{\n");
dvander@1965
  1933
dvander@1965
  1934
	num = 0;
dvander@1965
  1935
	aid = m_FirstUser;
dvander@1965
  1936
	while (aid != INVALID_ADMIN_ID
dvander@1965
  1937
			&& (pAdmin = GetUser(aid)) != NULL)
dvander@1965
  1938
	{
dvander@1965
  1939
		num++;
dvander@1965
  1940
		FillFlagString(pAdmin->flags, flagstr, sizeof(flagstr));
dvander@1965
  1941
dvander@1965
  1942
		fprintf(fp, "\t/* num = %d, aid = 0x%X, serialno = 0x%X*/\n", num, aid, pAdmin->serialchange);
dvander@1965
  1943
dvander@1965
  1944
		if (pAdmin->nameidx != -1)
dvander@1965
  1945
		{
dvander@1965
  1946
			fprintf(fp, "\t\"%s\"\n\t{\n", GetString(pAdmin->nameidx));
dvander@1965
  1947
		}
dvander@1965
  1948
		else
dvander@1965
  1949
		{
dvander@1965
  1950
			fprintf(fp, "\t\"\"\n\t{\n");
dvander@1965
  1951
		}
dvander@1965
  1952
dvander@1965
  1953
		if (pAdmin->auth.identidx != -1)
dvander@1965
  1954
		{
dvander@1965
  1955
			fprintf(fp, "\t\t\"auth\"\t\t\t\"%s\"\n", GetMethodName(pAdmin->auth.index));
dvander@1965
  1956
			fprintf(fp, "\t\t\"identity\"\t\t\"%s\"\n", GetString(pAdmin->auth.identidx));
dvander@1965
  1957
		}
dvander@1965
  1958
		if (pAdmin->password != -1)
dvander@1965
  1959
		{
dvander@1965
  1960
			fprintf(fp, "\t\t\"password\"\t\t\"%s\"\n", GetString(pAdmin->password));
dvander@1965
  1961
		}
dvander@1965
  1962
		fprintf(fp, "\t\t\"flags\"\t\t\t\"%s\"\n", flagstr);
dvander@1965
  1963
		fprintf(fp, "\t\t\"immunity\"\t\t\"%d\"\n", pAdmin->immunity_level);
dvander@1965
  1964
dvander@1965
  1965
		if (pAdmin->grp_count != 0 
dvander@1965
  1966
			&& pAdmin->grp_table != -1 
dvander@1965
  1967
			&& (itable = (int *)m_pMemory->GetAddress(pAdmin->grp_table)) != NULL)
dvander@1965
  1968
		{
dvander@1965
  1969
			unsigned int i;
dvander@1965
  1970
dvander@1965
  1971
			for (i = 0; i < pAdmin->grp_count; i++)
dvander@1965
  1972
			{
dvander@1965
  1973
				if ((pGroup = GetGroup(itable[i])) == NULL)
dvander@1965
  1974
				{
dvander@1965
  1975
					/* Assume the rest of the table is corrupt */
dvander@1965
  1976
					break;
dvander@1965
  1977
				}
dvander@1965
  1978
				fprintf(fp, "\t\t\"group\"\t\t\t\"%s\"\n", GetString(pGroup->nameidx));
dvander@1965
  1979
			}
dvander@1965
  1980
		}
dvander@1965
  1981
dvander@1965
  1982
		fprintf(fp, "\t}\n");
dvander@1965
  1983
dvander@1965
  1984
		if ((aid = pAdmin->next_user) != INVALID_ADMIN_ID)
dvander@1965
  1985
		{
dvander@1965
  1986
			fprintf(fp, "\n");
dvander@1965
  1987
		}
dvander@1965
  1988
	}
dvander@1965
  1989
dvander@1965
  1990
	fprintf(fp, "}\n\n");
dvander@1965
  1991
dvander@1965
  1992
	fprintf(fp, "\"Overrides\"\n{\n");
dvander@1965
  1993
	if (m_pCmdGrpOverrides != NULL)
dvander@1965
  1994
	{
dvander@1965
  1995
		sm_trie_bad_iterator(m_pCmdGrpOverrides,
dvander@1965
  1996
			name_buffer,
dvander@1965
  1997
			sizeof(name_buffer),
dvander@1965
  1998
			iterator_glob_grp_override,
dvander@1965
  1999
			fp);
dvander@1965
  2000
	}
dvander@1965
  2001
	if (m_pCmdOverrides != NULL)
dvander@1965
  2002
	{
dvander@1965
  2003
		sm_trie_bad_iterator(m_pCmdOverrides,
dvander@1965
  2004
			name_buffer, 
dvander@1965
  2005
			sizeof(name_buffer), 
dvander@1965
  2006
			iterator_glob_basic_override, 
dvander@1965
  2007
			fp);
dvander@1965
  2008
	}
dvander@1965
  2009
	fprintf(fp, "}\n");
dvander@1965
  2010
}
dvander@1965
  2011
dvander@1965
  2012
AdminGroup *AdminCache::GetGroup(GroupId gid)
dvander@1965
  2013
{
dvander@1965
  2014
	AdminGroup *pGroup;
dvander@1965
  2015
	
dvander@1965
  2016
	pGroup = (AdminGroup *)m_pMemory->GetAddress(gid);
dvander@1965
  2017
	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
dvander@1965
  2018
	{
dvander@1965
  2019
		return NULL;
dvander@1965
  2020
	}
dvander@1965
  2021
dvander@1965
  2022
	return pGroup;
dvander@1965
  2023
}
dvander@1965
  2024
dvander@1965
  2025
AdminUser *AdminCache::GetUser(AdminId aid)
dvander@1965
  2026
{
dvander@1965
  2027
	AdminUser *pAdmin;
dvander@1965
  2028
dvander@1965
  2029
	pAdmin = (AdminUser *)m_pMemory->GetAddress(aid);
dvander@1965
  2030
	if (!pAdmin || pAdmin->magic != USR_MAGIC_SET)
dvander@1965
  2031
	{
dvander@1965
  2032
		return NULL;
dvander@1965
  2033
	}
dvander@1965
  2034
dvander@1965
  2035
	return pAdmin;
dvander@1965
  2036
}
dvander@1965
  2037
dvander@1965
  2038
const char *AdminCache::GetMethodName(unsigned int index)
dvander@1965
  2039
{
dvander@1965
  2040
	List<AuthMethod>::iterator iter;
dvander@1965
  2041
	for (iter=m_AuthMethods.begin();
dvander@1965
  2042
		iter!=m_AuthMethods.end();
dvander@1965
  2043
		iter++)
dvander@1965
  2044
	{
dvander@1965
  2045
		if (index-- == 0)
dvander@1965
  2046
		{
dvander@1965
  2047
			return (*iter).name.c_str();
dvander@1965
  2048
		}
dvander@1965
  2049
	}
dvander@1965
  2050
dvander@1965
  2051
	return NULL;
dvander@1965
  2052
}
dvander@1965
  2053
dvander@1965
  2054
const char *AdminCache::GetString(int idx)
dvander@1965
  2055
{
dvander@1965
  2056
	return m_pStrings->GetString(idx);
dvander@1965
  2057
}
dvander@1965
  2058
dvander@1965
  2059
size_t AdminCache::FillFlagString(FlagBits bits, char *buffer, size_t maxlen)
dvander@1965
  2060
{
dvander@1965
  2061
	size_t pos;
dvander@1965
  2062
	unsigned int i, num_flags;
dvander@1965
  2063
	AdminFlag flags[AdminFlags_TOTAL];
dvander@1965
  2064
dvander@1965
  2065
	num_flags = FlagBitsToArray(bits, flags, AdminFlags_TOTAL);
dvander@1965
  2066
dvander@1965
  2067
	pos = 0;
dvander@1965
  2068
	for (i = 0; pos < maxlen && i < num_flags; i++)
dvander@1965
  2069
	{
dvander@1965
  2070
		if (FindFlagChar(flags[i], &buffer[pos]))
dvander@1965
  2071
		{
dvander@1965
  2072
			pos++;
dvander@1965
  2073
		}
dvander@1965
  2074
	}
dvander@1965
  2075
	buffer[pos] = '\0';
dvander@1965
  2076
dvander@1965
  2077
	return pos;
dvander@1965
  2078
}
dvander@1965
  2079
dvander@1965
  2080
CON_COMMAND(sm_dump_admcache, "Dumps the admin cache for debugging")
dvander@1965
  2081
{
dvander@1965
  2082
	FILE *fp;
dvander@1965
  2083
	char buffer[PLATFORM_MAX_PATH];
dvander@1965
  2084
dvander@1965
  2085
	g_SourceMod.BuildPath(Path_SM, buffer, sizeof(buffer), "data/admin_cache_dump.txt");
dvander@1965
  2086
dvander@1965
  2087
	if ((fp = fopen(buffer, "wt")) == NULL)
dvander@1965
  2088
	{
dvander@1965
  2089
		g_RootMenu.ConsolePrint("Could not open file for writing: %s", buffer);
dvander@1965
  2090
		return;
dvander@1965
  2091
	}
dvander@1965
  2092
dvander@1965
  2093
	g_Admins.DumpCache(fp);
dvander@1965
  2094
dvander@1965
  2095
	g_RootMenu.ConsolePrint("Admin cache dumped to: %s", buffer);
dvander@1965
  2096
dvander@1965
  2097
	fclose(fp);
dvander@1965
  2098
}