core/AdminCache.cpp
author Borja Ferrer <faluco@alliedmods.net>
Sun Feb 04 22:41:44 2007 +0000 (2007-02-04)
changeset 430 ed37e9767ed4
parent 425 d57bdb5a05bd
child 433 d699e31199ad
permissions -rw-r--r--
Optimized forwards, now paused functions are stored in a temp list so we dont have to check if they're runnable on each function execution.
     1 /**
     2  * ===============================================================
     3  * SourceMod (C)2004-2007 AlliedModders LLC.  All rights reserved.
     4  * ===============================================================
     5  *
     6  * This file is not open source and may not be copied without explicit
     7  * written permission of AlliedModders LLC.  This file may not be redistributed 
     8  * in whole or significant part.
     9  * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
    10  *
    11  * Version: $Id$
    12  */
    13 
    14 #include <string.h>
    15 #include <assert.h>
    16 #include "AdminCache.h"
    17 #include "ShareSys.h"
    18 #include "ForwardSys.h"
    19 
    20 AdminCache g_Admins;
    21 
    22 AdminCache::AdminCache()
    23 {
    24 	m_pCmdOverrides = NULL;
    25 	m_pCmdGrpOverrides = NULL;
    26 	m_pStrings = new BaseStringTable(1024);
    27 	m_pMemory = m_pStrings->GetMemTable();
    28 	m_FreeGroupList = m_FirstGroup = m_LastGroup = INVALID_GROUP_ID;
    29 	m_FreeUserList = m_FirstUser = m_LastUser = INVALID_ADMIN_ID;
    30 	m_pGroups = sm_trie_create();
    31 	m_pCacheFwd = NULL;
    32 	m_FirstGroup = -1;
    33 	m_pAuthTables = sm_trie_create();
    34 }
    35 
    36 AdminCache::~AdminCache()
    37 {
    38 	if (m_pCmdGrpOverrides)
    39 	{
    40 		sm_trie_destroy(m_pCmdGrpOverrides);
    41 	}
    42 
    43 	if (m_pCmdOverrides)
    44 	{
    45 		sm_trie_destroy(m_pCmdOverrides);
    46 	}
    47 
    48 	DumpAdminCache(0xFFFFFFFF, false);
    49 
    50 	if (m_pGroups)
    51 	{
    52 		sm_trie_destroy(m_pGroups);
    53 	}
    54 
    55 	List<AuthMethod>::iterator iter;
    56 	for (iter=m_AuthMethods.begin();
    57 		 iter!=m_AuthMethods.end();
    58 		 iter++)
    59 	{
    60 		sm_trie_destroy((*iter).table);
    61 	}
    62 
    63 	sm_trie_destroy(m_pAuthTables);
    64 
    65 	delete m_pStrings;
    66 }
    67 
    68 void AdminCache::OnSourceModStartup(bool late)
    69 {
    70 	RegisterAuthIdentType("steam");
    71 	RegisterAuthIdentType("name");
    72 	RegisterAuthIdentType("ip");
    73 }
    74 
    75 void AdminCache::OnSourceModAllInitialized()
    76 {
    77 	m_pCacheFwd = g_Forwards.CreateForward("OnRebuildAdminCache", ET_Ignore, 1, NULL, Param_Cell);
    78 	g_ShareSys.AddInterface(NULL, this);
    79 }
    80 
    81 void AdminCache::OnSourceModShutdown()
    82 {
    83 	g_Forwards.ReleaseForward(m_pCacheFwd);
    84 	m_pCacheFwd = NULL;
    85 }
    86 
    87 void AdminCache::AddCommandOverride(const char *cmd, OverrideType type, AdminFlag flag)
    88 {
    89 	if (type == Override_Command)
    90 	{
    91 		_AddCommandOverride(cmd, flag);
    92 	} else if (type == Override_CommandGroup) {
    93 		_AddCommandGroupOverride(cmd, flag);
    94 	}
    95 }
    96 
    97 bool AdminCache::GetCommandOverride(const char *cmd, OverrideType type, AdminFlag *pFlag)
    98 {
    99 	if (type == Override_Command)
   100 	{
   101 		return _GetCommandOverride(cmd, pFlag);
   102 	} else if (type == Override_CommandGroup) {
   103 		return _GetCommandGroupOverride(cmd, pFlag);
   104 	}
   105 
   106 	return false;
   107 }
   108 
   109 void AdminCache::UnsetCommandOverride(const char *cmd, OverrideType type)
   110 {
   111 	if (type == Override_Command)
   112 	{
   113 		return _UnsetCommandOverride(cmd);
   114 	} else if (type == Override_CommandGroup) {
   115 		return _UnsetCommandGroupOverride(cmd);
   116 	}
   117 }
   118 
   119 void AdminCache::_AddCommandGroupOverride(const char *group, AdminFlag flag)
   120 {
   121 	if (!m_pCmdGrpOverrides)
   122 	{
   123 		m_pCmdGrpOverrides = sm_trie_create();
   124 	}
   125 
   126 	/* :TODO: Notify command system */
   127 
   128 	sm_trie_insert(m_pCmdGrpOverrides, group, (void *)flag);
   129 }
   130 
   131 void AdminCache::_AddCommandOverride(const char *cmd, AdminFlag flag)
   132 {
   133 	if (!m_pCmdOverrides)
   134 	{
   135 		m_pCmdOverrides = sm_trie_create();
   136 	}
   137 
   138 	/* :TODO: Notify command system */
   139 
   140 	sm_trie_insert(m_pCmdOverrides, cmd, (void *)flag);
   141 }
   142 
   143 bool AdminCache::_GetCommandGroupOverride(const char *cmd, AdminFlag *pFlag)
   144 {
   145 	if (!m_pCmdGrpOverrides)
   146 	{
   147 		return false;
   148 	}
   149 
   150 	if (!pFlag)
   151 	{
   152 		return sm_trie_retrieve(m_pCmdGrpOverrides, cmd, NULL);
   153 	} else {
   154 		void *object;
   155 		bool ret;
   156 		if (ret=sm_trie_retrieve(m_pCmdGrpOverrides, cmd, &object))
   157 		{
   158 			*pFlag = (AdminFlag)(int)object;
   159 		}
   160 		return ret;
   161 	}
   162 }
   163 
   164 bool AdminCache::_GetCommandOverride(const char *cmd, AdminFlag *pFlag)
   165 {
   166 	if (!m_pCmdOverrides)
   167 	{
   168 		return false;
   169 	}
   170 
   171 	if (!pFlag)
   172 	{
   173 		return sm_trie_retrieve(m_pCmdOverrides, cmd, NULL);
   174 	} else {
   175 		void *object;
   176 		bool ret;
   177 		if (ret=sm_trie_retrieve(m_pCmdOverrides, cmd, &object))
   178 		{
   179 			*pFlag = (AdminFlag)(int)object;
   180 		}
   181 		return ret;
   182 	}
   183 }
   184 
   185 void AdminCache::_UnsetCommandGroupOverride(const char *group)
   186 {
   187 	if (!m_pCmdGrpOverrides)
   188 	{
   189 		return;
   190 	}
   191 
   192 	/* :TODO: Notify command system */
   193 
   194 	sm_trie_delete(m_pCmdGrpOverrides, group);
   195 }
   196 
   197 void AdminCache::_UnsetCommandOverride(const char *cmd)
   198 {
   199 	if (!m_pCmdOverrides)
   200 	{
   201 		return;
   202 	}
   203 
   204 	/* :TODO: Notify command system */
   205 
   206 	sm_trie_delete(m_pCmdOverrides, cmd);
   207 }
   208 
   209 void AdminCache::DumpCommandOverrideCache(OverrideType type)
   210 {
   211 	if (type == Override_Command && m_pCmdOverrides)
   212 	{
   213 		sm_trie_clear(m_pCmdOverrides);
   214 	} else if (type == Override_CommandGroup && m_pCmdGrpOverrides) {
   215 		sm_trie_clear(m_pCmdGrpOverrides);
   216 	}
   217 }
   218 
   219 AdminId AdminCache::CreateAdmin(const char *name)
   220 {
   221 	AdminId id;
   222 	AdminUser *pUser;
   223 
   224 	if (m_FreeUserList != INVALID_ADMIN_ID)
   225 	{
   226 		pUser = (AdminUser *)m_pMemory->GetAddress(m_FreeUserList);
   227 		assert(pUser->magic == USR_MAGIC_UNSET);
   228 		id = m_FreeUserList;
   229 		m_FreeUserList = pUser->next_user;
   230 	} else {
   231 		id = m_pMemory->CreateMem(sizeof(AdminUser), (void **)&pUser);
   232 		pUser->grp_size = 0;
   233 		pUser->grp_table = -1;
   234 	}
   235 
   236 	memset(pUser->flags, 0, sizeof(pUser->flags));
   237 	memset(pUser->eflags, 0, sizeof(pUser->flags));
   238 	pUser->grp_count = 0;
   239 	pUser->password = -1;
   240 	pUser->magic = USR_MAGIC_SET;
   241 	pUser->auth.identidx = -1;
   242 	pUser->auth.index = 0;
   243 
   244 	if (m_FirstUser == INVALID_ADMIN_ID)
   245 	{
   246 		m_FirstUser = id;
   247 		m_LastUser = id;
   248 	} else {
   249 		AdminUser *pPrev = (AdminUser *)m_pMemory->GetAddress(m_LastUser);
   250 		pPrev->next_user = id;
   251 		pUser->prev_user = m_LastUser;
   252 		m_LastUser = id;
   253 	}
   254 
   255 	if (name && name[0] != '\0')
   256 	{
   257 		pUser->nameidx = m_pStrings->AddString(name);
   258 	}
   259 
   260 	return id;
   261 }
   262 
   263 GroupId AdminCache::AddGroup(const char *group_name)
   264 {
   265 	if (sm_trie_retrieve(m_pGroups, group_name, NULL))
   266 	{
   267 		return INVALID_GROUP_ID;
   268 	}
   269 
   270 	GroupId id;
   271 	AdminGroup *pGroup;
   272 	if (m_FreeGroupList != INVALID_GROUP_ID)
   273 	{
   274 		pGroup = (AdminGroup *)m_pMemory->GetAddress(m_FreeGroupList);
   275 		assert(pGroup->magic == GRP_MAGIC_UNSET);
   276 		id = m_FreeGroupList;
   277 		m_FreeGroupList = pGroup->next_grp;
   278 	} else {
   279 		id = m_pMemory->CreateMem(sizeof(AdminGroup), (void **)&pGroup);
   280 	}
   281 
   282 	pGroup->immune_default = false;
   283 	pGroup->immune_global = false;
   284 	pGroup->immune_table = -1;
   285 	pGroup->magic = GRP_MAGIC_SET;
   286 	pGroup->next_grp = INVALID_GROUP_ID;
   287 	pGroup->pCmdGrpTable = NULL;
   288 	pGroup->pCmdTable = NULL;
   289 	memset(pGroup->addflags, 0, sizeof(AdminFlag) * AdminFlags_TOTAL);
   290 
   291 	if (m_FirstGroup == INVALID_GROUP_ID)
   292 	{
   293 		m_FirstGroup = id;
   294 		m_LastGroup = id;
   295 		pGroup->prev_grp = INVALID_GROUP_ID;
   296 	} else {
   297 		AdminGroup *pPrev = (AdminGroup *)m_pMemory->GetAddress(m_LastGroup);
   298 		assert(pPrev->magic == GRP_MAGIC_SET);
   299 		pPrev->next_grp = id;
   300 		pGroup->prev_grp = m_LastGroup;
   301 		m_LastGroup = id;
   302 	}
   303 
   304 	pGroup->nameidx = m_pStrings->AddString(group_name);
   305 
   306 	sm_trie_insert(m_pGroups, group_name, (void *)id);
   307 
   308 	return id;
   309 }
   310 
   311 GroupId AdminCache::FindGroupByName(const char *group_name)
   312 {
   313 	void *object;
   314 
   315 	if (!sm_trie_retrieve(m_pGroups, group_name, &object))
   316 	{
   317 		return INVALID_GROUP_ID;
   318 	}
   319 
   320 	GroupId id = (GroupId)object;
   321 	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
   322 
   323 	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
   324 	{
   325 		return INVALID_GROUP_ID;
   326 	}
   327 
   328 	return id;
   329 }
   330 
   331 void AdminCache::SetGroupAddFlag(GroupId id, AdminFlag flag, bool enabled)
   332 {
   333 	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
   334 	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
   335 	{
   336 		return;
   337 	}
   338 
   339 	if (flag < Admin_None || flag >= AdminFlags_TOTAL)
   340 	{
   341 		return;
   342 	}
   343 
   344 	pGroup->addflags[flag] = enabled;
   345 }
   346 
   347 bool AdminCache::GetGroupAddFlag(GroupId id, AdminFlag flag)
   348 {
   349 	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
   350 	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
   351 	{
   352 		return false;
   353 	}
   354 
   355 	if (flag < Admin_None || flag >= AdminFlags_TOTAL)
   356 	{
   357 		return false;
   358 	}
   359 
   360 	return pGroup->addflags[flag];
   361 }
   362 
   363 unsigned int AdminCache::GetGroupAddFlagBits(GroupId id, bool flags[], unsigned int total)
   364 {
   365 	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
   366 	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
   367 	{
   368 		return 0;
   369 	}
   370 
   371 	unsigned int i;
   372 
   373 	for (i = Admin_None;
   374 		 i < AdminFlags_TOTAL && i < total;
   375 		 i++)
   376 	{
   377 		flags[i] = pGroup->addflags[i];
   378 	}
   379 
   380 	return i;
   381 }
   382 
   383 void AdminCache::SetGroupGenericImmunity(GroupId id, ImmunityType type, bool enabled)
   384 {
   385 	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
   386 	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
   387 	{
   388 		return;
   389 	}
   390 
   391 	if (type == Immunity_Default)
   392 	{
   393 		pGroup->immune_default = enabled;
   394 	} else if (type == Immunity_Global) {
   395 		pGroup->immune_global = enabled;
   396 	} 
   397 }
   398 
   399 bool AdminCache::GetGroupGenericImmunity(GroupId id, ImmunityType type)
   400 {
   401 	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
   402 	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
   403 	{
   404 		return false;
   405 	}
   406 
   407 	if (type == Immunity_Default)
   408 	{
   409 		return pGroup->immune_default;
   410 	} else if (type == Immunity_Global) {
   411 		return pGroup->immune_global;
   412 	}
   413 
   414 	return false;
   415 }
   416 
   417 void AdminCache::AddGroupImmunity(GroupId id, GroupId other_id)
   418 {
   419 	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
   420 	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
   421 	{
   422 		return;
   423 	}
   424 
   425 	AdminGroup *pOther = (AdminGroup *)m_pMemory->GetAddress(id);
   426 	if (!pOther || pOther->magic != GRP_MAGIC_SET)
   427 	{
   428 		return;
   429 	}
   430 
   431 	/* We always need to resize the immunity table */
   432 	int *table, tblidx;
   433 	if (pOther->immune_table == -1)
   434 	{
   435 		tblidx = m_pMemory->CreateMem(sizeof(int) * 2, (void **)&table);
   436 		table[0] = 0;
   437 	} else {
   438 		int *old_table = (int *)m_pMemory->GetAddress(pOther->immune_table);
   439 		tblidx = m_pMemory->CreateMem(sizeof(int) * (old_table[0] + 2), (void **)&table);
   440 		/* Get the old address again in caes of resize */
   441 		old_table = (int *)m_pMemory->GetAddress(pOther->immune_table);
   442 		table[0] = old_table[0];
   443 		for (unsigned int i=1; i<=(unsigned int)old_table[0]; i++)
   444 		{
   445 			table[i] = old_table[i];
   446 		}
   447 	}
   448 
   449 	/* Assign */
   450 	pOther->immune_table = tblidx;
   451 
   452 	/* Add to the array */
   453 	table[0]++;
   454 	table[table[0]] = other_id;
   455 }
   456 
   457 unsigned int AdminCache::GetGroupImmunityCount(GroupId id)
   458 {
   459 	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
   460 	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
   461 	{
   462 		return 0;
   463 	}
   464 
   465 	if (pGroup->immune_table == -1)
   466 	{
   467 		return 0;
   468 	}
   469 
   470 	int *table = (int *)m_pMemory->GetAddress(pGroup->immune_table);
   471 
   472 	return table[0];
   473 }
   474 
   475 GroupId AdminCache::GetGroupImmunity(GroupId id, unsigned int number)
   476 {
   477 	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
   478 	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
   479 	{
   480 		return INVALID_GROUP_ID;
   481 	}
   482 
   483 	if (pGroup->immune_table == -1)
   484 	{
   485 		return INVALID_GROUP_ID;
   486 	}
   487 
   488 	int *table = (int *)m_pMemory->GetAddress(pGroup->immune_table);
   489 	if (number >= (unsigned int)table[0])
   490 	{
   491 		return INVALID_GROUP_ID;
   492 	}
   493 
   494 	return table[1 + number];
   495 }
   496 
   497 void AdminCache::AddGroupCommandOverride(GroupId id, const char *name, OverrideType type, OverrideRule rule)
   498 {
   499 	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
   500 	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
   501 	{
   502 		return;
   503 	}
   504 
   505 	Trie *pTrie = NULL;
   506 	if (type == Override_Command)
   507 	{
   508 		if (pGroup->pCmdTable == NULL)
   509 		{
   510 			pGroup->pCmdTable = sm_trie_create();
   511 		}
   512 		pTrie = pGroup->pCmdTable;
   513 	} else if (type == Override_CommandGroup) {
   514 		if (pGroup->pCmdGrpTable == NULL)
   515 		{
   516 			pGroup->pCmdGrpTable = sm_trie_create();
   517 		}
   518 		pTrie = pGroup->pCmdGrpTable;
   519 	} else {
   520 		return;
   521 	}
   522 
   523 	sm_trie_insert(pTrie, name, (void *)(int)rule);
   524 }
   525 
   526 bool AdminCache::GetGroupCommandOverride(GroupId id, const char *name, OverrideType type, OverrideRule *pRule)
   527 {
   528 	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
   529 	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
   530 	{
   531 		return false;
   532 	}
   533 
   534 	Trie *pTrie = NULL;
   535 	if (type == Override_Command)
   536 	{
   537 		if (pGroup->pCmdTable == NULL)
   538 		{
   539 			return false;
   540 		}
   541 		pTrie = pGroup->pCmdTable;
   542 	} else if (type == Override_CommandGroup) {
   543 		if (pGroup->pCmdGrpTable == NULL)
   544 		{
   545 			return false;
   546 		}
   547 		pTrie = pGroup->pCmdGrpTable;
   548 	} else {
   549 		return false;
   550 	}
   551 
   552 	void *object;
   553 	if (!sm_trie_retrieve(pTrie, name, &object))
   554 	{
   555 		return false;
   556 	}
   557 
   558 	if (pRule)
   559 	{
   560 		*pRule = (OverrideRule)(int)object;
   561 	}
   562 	
   563 	return true;
   564 }
   565 
   566 Trie *AdminCache::GetMethodByIndex(unsigned int index)
   567 {
   568 	List<AuthMethod>::iterator iter;
   569 	for (iter=m_AuthMethods.begin();
   570 		 iter!=m_AuthMethods.end();
   571 		 iter++)
   572 	{
   573 		if (index-- == 0)
   574 		{
   575 			return (*iter).table;
   576 		}
   577 	}
   578 
   579 	return NULL;
   580 }
   581 
   582 bool AdminCache::InvalidateAdmin(AdminId id)
   583 {
   584 	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
   585 	AdminUser *pOther;
   586 	if (!pUser || pUser->magic != USR_MAGIC_SET)
   587 	{
   588 		return false;
   589 	}
   590 
   591 	/* Unlink from the dbl link list */
   592 	if (id == m_FirstUser && id == m_LastUser)
   593 	{
   594 		m_FirstUser = INVALID_ADMIN_ID;
   595 		m_LastUser = INVALID_ADMIN_ID;
   596 	} else if (id == m_FirstUser) {
   597 		m_FirstUser = pUser->next_user;
   598 		pOther = (AdminUser *)m_pMemory->GetAddress(m_FirstUser);
   599 		pOther->prev_user = INVALID_ADMIN_ID;
   600 	} else if (id == m_LastUser) {
   601 		m_LastUser = pUser->prev_user;
   602 		pOther = (AdminUser *)m_pMemory->GetAddress(m_LastUser);
   603 		pOther->next_user = INVALID_ADMIN_ID;
   604 	} else {
   605 		pOther = (AdminUser *)m_pMemory->GetAddress(pUser->prev_user);
   606 		pOther->next_user = pUser->next_user;
   607 		pOther = (AdminUser *)m_pMemory->GetAddress(pUser->next_user);
   608 		pOther->prev_user = pUser->prev_user;
   609 	}
   610 
   611 	/* Unlink from auth tables */
   612 	if (pUser->auth.identidx != -1)
   613 	{
   614 		Trie *pTrie = GetMethodByIndex(pUser->auth.index);
   615 		if (pTrie)
   616 		{
   617 			sm_trie_delete(pTrie, m_pStrings->GetString(pUser->auth.identidx));
   618 		}
   619 	}
   620 
   621 	/* Clear table counts */
   622 	pUser->grp_count = 0;
   623 	
   624 	/* Link into free list */
   625 	pUser->magic = USR_MAGIC_UNSET;
   626 	pUser->next_user = m_FreeUserList;
   627 	m_FreeUserList = id;
   628 
   629 	return true;
   630 }
   631 
   632 
   633 void AdminCache::InvalidateGroup(GroupId id)
   634 {
   635 	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(id);
   636 	AdminGroup *pOther;
   637 
   638 	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
   639 	{
   640 		return;
   641 	}
   642 
   643 	const char *str = m_pStrings->GetString(pGroup->nameidx);
   644 	sm_trie_delete(m_pGroups, str);
   645 
   646 	/* Unlink from the live dbllink list */
   647 	if (id == m_FirstGroup && id == m_LastGroup)
   648 	{
   649 		m_LastGroup = INVALID_GROUP_ID;
   650 		m_FirstGroup = INVALID_GROUP_ID;
   651 	} else if (id == m_FirstGroup) {
   652 		m_FirstGroup = pGroup->next_grp;
   653 		pOther = (AdminGroup *)m_pMemory->GetAddress(m_FirstGroup);
   654 		pOther->prev_grp = INVALID_GROUP_ID;
   655 	} else if (id == m_LastGroup) {
   656 		m_LastGroup = pGroup->prev_grp;
   657 		pOther = (AdminGroup *)m_pMemory->GetAddress(m_LastGroup);
   658 		pOther->next_grp = INVALID_GROUP_ID;
   659 	} else {
   660 		pOther = (AdminGroup *)m_pMemory->GetAddress(pGroup->prev_grp);
   661 		pOther->next_grp = pGroup->next_grp;
   662 		pOther = (AdminGroup *)m_pMemory->GetAddress(pGroup->next_grp);
   663 		pOther->prev_grp = pGroup->prev_grp;
   664 	}
   665 
   666 	/* Free any used memory to be safe */
   667 	if (pGroup->pCmdGrpTable)
   668 	{
   669 		sm_trie_destroy(pGroup->pCmdGrpTable);
   670 		pGroup->pCmdGrpTable = NULL;
   671 	}
   672 	if (pGroup->pCmdTable)
   673 	{
   674 		sm_trie_destroy(pGroup->pCmdTable);
   675 		pGroup->pCmdTable = NULL;
   676 	}
   677 
   678 	/* Link into the free list */
   679 	pGroup->magic = GRP_MAGIC_UNSET;
   680 	pGroup->next_grp = m_FreeGroupList;
   681 	m_FreeGroupList = id;
   682 
   683 	int idx = m_FirstUser;
   684 	AdminUser *pUser;
   685 	int *table;
   686 	while (idx != INVALID_ADMIN_ID)
   687 	{
   688 		pUser = (AdminUser *)m_pMemory->GetAddress(idx);
   689 		if (pUser->grp_count > 0)
   690 		{
   691 			table = (int *)m_pMemory->GetAddress(pUser->grp_table);
   692 			for (unsigned int i=0; i<pUser->grp_count; i++)
   693 			{
   694 				if (table[i] == id)
   695 				{
   696 					/* We have to remove this entry */
   697 					for (unsigned int j=i+1; j<pUser->grp_count; j++)
   698 					{
   699 						/* Move everything down by one */
   700 						table[j-1] = table[j];
   701 					}
   702 					/* Decrease count */
   703 					pUser->grp_count--;
   704 					/* Recalculate effective flags */
   705 					memset(pUser->eflags, 0, sizeof(pUser->eflags));
   706 					for (unsigned int j=0; j<pUser->grp_count; j++)
   707 					{
   708 						pOther = (AdminGroup *)m_pMemory->GetAddress(table[j]);
   709 						for (unsigned int k=0; k<AdminFlags_TOTAL; k++)
   710 						{
   711 							pUser->eflags[k] = (pUser->flags[k] || pOther->addflags[k]);
   712 						}
   713 					}
   714 					/* Break now, duplicates aren't allowed */
   715 					break;
   716 				}
   717 			}
   718 		}
   719 		idx = pUser->next_user;
   720 	}
   721 }
   722 
   723 void AdminCache::InvalidateGroupCache()
   724 {
   725 	/* Nuke the free list */
   726 	m_FreeGroupList = -1;
   727 
   728 	/* Nuke reverse lookups */
   729 	sm_trie_clear(m_pGroups);
   730 
   731 	/* Free memory on groups */
   732 	GroupId cur = m_FirstGroup;
   733 	AdminGroup *pGroup;
   734 	while (cur != INVALID_GROUP_ID)
   735 	{
   736 		pGroup = (AdminGroup *)m_pMemory->GetAddress(cur);
   737 		assert(pGroup->magic == GRP_MAGIC_SET);
   738 		if (pGroup->pCmdGrpTable)
   739 		{
   740 			sm_trie_destroy(pGroup->pCmdGrpTable);
   741 		}
   742 		if (pGroup->pCmdTable)
   743 		{
   744 			sm_trie_destroy(pGroup->pCmdTable);
   745 		}
   746 		cur = pGroup->next_grp;
   747 	}
   748 
   749 	m_FirstGroup = INVALID_GROUP_ID;
   750 	m_LastGroup = INVALID_GROUP_ID;
   751 
   752 	InvalidateAdminCache(false);
   753 
   754 	/* Reset the memory table */
   755 	m_pMemory->Reset();
   756 }
   757 
   758 void AdminCache::AddAdminListener(IAdminListener *pListener)
   759 {
   760 	m_hooks.push_back(pListener);
   761 }
   762 
   763 void AdminCache::RemoveAdminListener(IAdminListener *pListener)
   764 {
   765 	m_hooks.remove(pListener);
   766 }
   767 
   768 void AdminCache::RegisterAuthIdentType(const char *name)
   769 {
   770 	if (sm_trie_retrieve(m_pAuthTables, name, NULL))
   771 	{
   772 		return;
   773 	}
   774 
   775 	Trie *pAuth = sm_trie_create();
   776 
   777 	AuthMethod method;
   778 	method.name.assign(name);
   779 	method.table = pAuth;
   780 
   781 	m_AuthMethods.push_back(method);
   782 
   783 	sm_trie_insert(m_pAuthTables, name, pAuth);
   784 }
   785 
   786 void AdminCache::InvalidateAdminCache(bool unlink_admins)
   787 {
   788 	/* Wipe the identity cache first */
   789 	List<AuthMethod>::iterator iter;
   790 	for (iter=m_AuthMethods.begin();
   791 		 iter!=m_AuthMethods.end();
   792 		 iter++)
   793 	{
   794 		sm_trie_clear((*iter).table);
   795 	}
   796 	
   797 	if (unlink_admins)
   798 	{
   799 		while (m_FirstUser != INVALID_ADMIN_ID)
   800 		{
   801 			InvalidateAdmin(m_FirstUser);
   802 		}
   803 	} else {
   804 		m_FirstUser = -1;
   805 		m_LastUser = -1;
   806 		m_FreeUserList = -1;
   807 	}
   808 }
   809 
   810 void AdminCache::DumpAdminCache(int cache_flags, bool rebuild)
   811 {
   812 	if (cache_flags & ADMIN_CACHE_OVERRIDES)
   813 	{
   814 		DumpCommandOverrideCache(Override_Command);
   815 		DumpCommandOverrideCache(Override_CommandGroup);
   816 	}
   817 
   818 	/* This will auto-invalidate the admin cache */
   819 	if (cache_flags & ADMIN_CACHE_GROUPS)
   820 	{
   821 		InvalidateGroupCache();
   822 	}
   823 
   824 	/* If we only requested an admin rebuild, re-use the internal memory */
   825 	if (((cache_flags & ADMIN_CACHE_ADMINS) == ADMIN_CACHE_ADMINS)
   826 		&& ((cache_flags & (1<<2)) != (1<<2)))
   827 	{
   828 		InvalidateAdminCache(true);
   829 	}
   830 
   831 	if (rebuild)
   832 	{
   833 		List<IAdminListener *>::iterator iter;
   834 		IAdminListener *pListener;
   835 		cell_t result;
   836 		for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
   837 		{
   838 			pListener = (*iter);
   839 			pListener->OnRebuildAdminCache(cache_flags);
   840 		}
   841 		m_pCacheFwd->PushCell(cache_flags);
   842 		m_pCacheFwd->Execute(&result);
   843 	}
   844 }
   845 
   846 const char *AdminCache::GetAdminName(AdminId id)
   847 {
   848 	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
   849 	if (!pUser || pUser->magic != USR_MAGIC_SET)
   850 	{
   851 		return NULL;
   852 	}
   853 
   854 	return m_pStrings->GetString(pUser->nameidx);
   855 }
   856 
   857 bool AdminCache::GetMethodIndex(const char *name, unsigned int *_index)
   858 {
   859 	List<AuthMethod>::iterator iter;
   860 	unsigned int index = 0;
   861 	for (iter=m_AuthMethods.begin();
   862 		 iter!=m_AuthMethods.end();
   863 		 iter++,index++)
   864 	{
   865 		if ((*iter).name.compare(name) == 0)
   866 		{
   867 			*_index = index;
   868 			return true;
   869 		}
   870 	}
   871 
   872 	return false;
   873 }
   874 
   875 bool AdminCache::BindAdminIdentity(AdminId id, const char *auth, const char *ident)
   876 {
   877 	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
   878 	if (!pUser || pUser->magic != USR_MAGIC_SET)
   879 	{
   880 		return false;
   881 	}
   882 
   883 	Trie *pTable;
   884 	if (!sm_trie_retrieve(m_pAuthTables, auth, (void **)&pTable))
   885 	{
   886 		return false;
   887 	}
   888 
   889 	if (sm_trie_retrieve(pTable, ident, NULL))
   890 	{
   891 		return false;
   892 	}
   893 
   894 	pUser->auth.identidx = m_pStrings->AddString(ident);
   895 	GetMethodIndex(auth, &pUser->auth.index);
   896 
   897 	return sm_trie_insert(pTable, ident, (void **)id);
   898 }
   899 
   900 AdminId AdminCache::FindAdminByIdentity(const char *auth, const char *identity)
   901 {
   902 	Trie *pTable;
   903 	if (!sm_trie_retrieve(m_pAuthTables, auth, (void **)&pTable))
   904 	{
   905 		return INVALID_ADMIN_ID;
   906 	}
   907 
   908 	void *object;
   909 	if (!sm_trie_retrieve(pTable, identity, &object))
   910 	{
   911 		return INVALID_ADMIN_ID;
   912 	}
   913 
   914 	return (AdminId)object;
   915 }
   916 
   917 void AdminCache::SetAdminFlag(AdminId id, AdminFlag flag, bool enabled)
   918 {
   919 	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
   920 	if (!pUser || pUser->magic != USR_MAGIC_SET)
   921 	{
   922 		return;
   923 	}
   924 
   925 	if (flag < Admin_None
   926 		|| flag >= AdminFlags_TOTAL)
   927 	{
   928 		return;
   929 	}
   930 
   931 	pUser->flags[enabled] = false;
   932 }
   933 
   934 bool AdminCache::GetAdminFlag(AdminId id, AdminFlag flag, AccessMode mode)
   935 {
   936 	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
   937 	if (!pUser || pUser->magic != USR_MAGIC_SET)
   938 	{
   939 		return false;
   940 	}
   941 
   942 	if (flag < Admin_None
   943 		|| flag >= AdminFlags_TOTAL)
   944 	{
   945 		return false;
   946 	}
   947 
   948 	if (mode == Access_Real)
   949 	{
   950 		return pUser->flags[flag];
   951 	} else if (mode == Access_Effective) {
   952 		return (pUser->flags[flag] || pUser->eflags[flag]);
   953 	}
   954 
   955 	return false;
   956 }
   957 
   958 unsigned int AdminCache::GetAdminFlags(AdminId id, bool flags[], unsigned int total, AccessMode mode)
   959 {
   960 	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
   961 	if (!pUser || pUser->magic != USR_MAGIC_SET)
   962 	{
   963 		return 0;
   964 	}
   965 
   966 	unsigned int i = 0;
   967 	if (mode == Access_Real)
   968 	{
   969 		for (i=0; i<AdminFlags_TOTAL && i<total; i++)
   970 		{
   971 			flags[i] = pUser->flags[i];
   972 		}
   973 	} else if (mode == Access_Effective) {
   974 		for (i=0; i<AdminFlags_TOTAL && i<total; i++)
   975 		{
   976 			flags[i] = (pUser->flags[i] || pUser->eflags[i]);
   977 		}
   978 	}
   979 
   980 	return i;
   981 }
   982 
   983 bool AdminCache::AdminInheritGroup(AdminId id, GroupId gid)
   984 {
   985 	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
   986 	if (!pUser || pUser->magic != USR_MAGIC_SET)
   987 	{
   988 		return false;
   989 	}
   990 
   991 	AdminGroup *pGroup = (AdminGroup *)m_pMemory->GetAddress(gid);
   992 	if (!pGroup || pGroup->magic != GRP_MAGIC_SET)
   993 	{
   994 		return false;
   995 	}
   996 
   997 	int *table;
   998 	if (pUser->grp_count + 1 > pUser->grp_size)
   999 	{
  1000 		int new_size = 0;
  1001 		int tblidx;
  1002 		
  1003 		if (pUser->grp_size == 0)
  1004 		{
  1005 			new_size = 2;
  1006 		} else {
  1007 			new_size = pUser->grp_size * 2;
  1008 		}
  1009 		
  1010 		/* Create and refresh pointers */
  1011 		tblidx = m_pMemory->CreateMem(new_size * sizeof(int), (void **)&table);
  1012 		pUser = (AdminUser *)m_pMemory->GetAddress(id);
  1013 		pGroup = (AdminGroup *)m_pMemory->GetAddress(gid);
  1014 
  1015 		/* Copy old data if necessary */
  1016 		if (pUser->grp_table != -1)
  1017 		{
  1018 			int *old_table = (int *)m_pMemory->GetAddress(pUser->grp_table);
  1019 			memcpy(table, old_table, sizeof(int) * pUser->grp_count);
  1020 		}
  1021 		pUser->grp_table = tblidx;
  1022 		pUser->grp_size = new_size;
  1023 	} else {
  1024 		table = (int *)m_pMemory->GetAddress(pUser->grp_table);
  1025 	}
  1026 
  1027 	for (unsigned int i=0; i<pUser->grp_count; i++)
  1028 	{
  1029 		if (table[i] == gid)
  1030 		{
  1031 			return false;
  1032 		}
  1033 	}
  1034 
  1035 	table[pUser->grp_count] = gid;
  1036 	pUser->grp_count++;
  1037 
  1038 	/* Compute new effective flags */
  1039 	for (unsigned int i=Admin_None;
  1040 		 i<AdminFlags_TOTAL;
  1041 		 i++)
  1042 	{
  1043 		/* Only inherit flags additive flags we don't have */
  1044 		if (!pUser->eflags[i])
  1045 		{
  1046 			pUser->eflags[i] = pGroup->addflags[i];
  1047 		}
  1048 	}
  1049 
  1050 	return true;
  1051 }
  1052 
  1053 unsigned int AdminCache::GetAdminGroupCount(AdminId id)
  1054 {
  1055 	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
  1056 	if (!pUser || pUser->magic != USR_MAGIC_SET)
  1057 	{
  1058 		return 0;
  1059 	}
  1060 
  1061 	return pUser->grp_count;
  1062 }
  1063 
  1064 GroupId AdminCache::GetAdminGroup(AdminId id, unsigned int index, const char **name)
  1065 {
  1066 	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
  1067 	if (!pUser || pUser->magic != USR_MAGIC_SET || index >= pUser->grp_count)
  1068 	{
  1069 		return INVALID_GROUP_ID;
  1070 	}
  1071 
  1072 	int *table = (int *)m_pMemory->GetAddress(pUser->grp_table);
  1073 
  1074 	return table[index];
  1075 }
  1076 
  1077 const char *AdminCache::GetAdminPassword(AdminId id)
  1078 {
  1079 	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
  1080 	if (!pUser || pUser->magic != USR_MAGIC_SET)
  1081 	{
  1082 		return NULL;
  1083 	}
  1084 
  1085 	return m_pStrings->GetString(pUser->password);
  1086 }
  1087 
  1088 void AdminCache::SetAdminPassword(AdminId id, const char *password)
  1089 {	
  1090 	AdminUser *pUser = (AdminUser *)m_pMemory->GetAddress(id);
  1091 	if (!pUser || pUser->magic != USR_MAGIC_SET)
  1092 	{
  1093 		return;
  1094 	}
  1095 
  1096 	pUser->password = m_pStrings->AddString(password);
  1097 }
  1098