core/CConCmdManager.cpp
author David Anderson <dvander@alliedmods.net>
Sat Feb 17 09:02:22 2007 +0000 (2007-02-17)
changeset 516 0807e52b4e02
parent 514 4c02b38c26ed
child 520 7676d61cde2d
permissions -rw-r--r--
clientconnect now blocks properly when needed
removed cruft
ds@504
     1
/**
ds@504
     2
* ===============================================================
ds@504
     3
* SourceMod (C)2004-2007 AlliedModders LLC.  All rights reserved.
ds@504
     4
* ===============================================================
ds@504
     5
*
ds@504
     6
* This file is not open source and may not be copied without explicit
ds@504
     7
* written permission of AlliedModders LLC.  This file may not be redistributed 
ds@504
     8
* in whole or significant part.
ds@504
     9
* For information, see LICENSE.txt or http://www.sourcemod.net/license.php
ds@504
    10
*
ds@504
    11
* Version: $Id$
ds@504
    12
*/
ds@504
    13
dvander@498
    14
#include "CConCmdManager.h"
dvander@498
    15
#include "sm_srvcmds.h"
dvander@513
    16
#include "AdminCache.h"
ds@504
    17
#include "sm_stringutil.h"
dvander@514
    18
#include "CPlayerManager.h"
dvander@514
    19
#include "CTranslator.h"
dvander@498
    20
dvander@498
    21
CConCmdManager g_ConCmds;
dvander@498
    22
dvander@498
    23
SH_DECL_HOOK0_void(ConCommand, Dispatch, SH_NOATTRIB, false);
dvander@498
    24
SH_DECL_HOOK1_void(IServerGameClients, SetCommandClient, SH_NOATTRIB, false, int);
dvander@498
    25
dvander@498
    26
struct PlCmdInfo
dvander@498
    27
{
dvander@498
    28
	ConCmdInfo *pInfo;
dvander@513
    29
	CmdHook *pHook;
dvander@498
    30
	CmdType type;
dvander@498
    31
};
dvander@513
    32
typedef List<PlCmdInfo> CmdList;
dvander@513
    33
void AddToPlCmdList(CmdList *pList, const PlCmdInfo &info);
dvander@498
    34
dvander@513
    35
CConCmdManager::CConCmdManager() : m_Strings(1024)
dvander@498
    36
{
dvander@498
    37
	m_pCmds = sm_trie_create();
dvander@513
    38
	m_pCmdGrps = sm_trie_create();
dvander@498
    39
}
dvander@498
    40
dvander@498
    41
CConCmdManager::~CConCmdManager()
dvander@498
    42
{
dvander@498
    43
	sm_trie_destroy(m_pCmds);
dvander@513
    44
	sm_trie_destroy(m_pCmdGrps);
dvander@498
    45
}
dvander@498
    46
dvander@498
    47
void CConCmdManager::OnSourceModAllInitialized()
dvander@498
    48
{
dvander@498
    49
	g_PluginSys.AddPluginsListener(this);
dvander@498
    50
	g_RootMenu.AddRootConsoleCommand("cmds", "List console commands", this);
dvander@498
    51
	SH_ADD_HOOK_MEMFUNC(IServerGameClients, SetCommandClient, serverClients, this, &CConCmdManager::SetCommandClient, false);
dvander@498
    52
}
dvander@498
    53
dvander@498
    54
void CConCmdManager::OnSourceModShutdown()
dvander@498
    55
{
dvander@500
    56
	/* All commands should already be removed by the time we're done */
dvander@498
    57
	SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, SetCommandClient, serverClients, this, &CConCmdManager::SetCommandClient, false);
dvander@498
    58
	g_RootMenu.RemoveRootConsoleCommand("cmds", this);
dvander@498
    59
	g_PluginSys.RemovePluginsListener(this);
dvander@498
    60
}
dvander@498
    61
dvander@513
    62
void CConCmdManager::RemoveConCmds(List<CmdHook *> &cmdlist, IPluginContext *pContext)
dvander@498
    63
{
dvander@513
    64
	List<CmdHook *>::iterator iter = cmdlist.begin();
dvander@513
    65
	CmdHook *pHook;
dvander@513
    66
dvander@513
    67
	while (iter != cmdlist.end())
dvander@513
    68
	{
dvander@513
    69
		pHook = (*iter);
dvander@513
    70
		if (pHook->pf->GetParentContext() == pContext)
dvander@513
    71
		{
dvander@513
    72
			delete pHook->pAdmin;
dvander@513
    73
			delete pHook;
dvander@513
    74
			iter = cmdlist.erase(iter);
dvander@513
    75
		} else {
dvander@513
    76
			iter++;
dvander@513
    77
		}
dvander@513
    78
	}
dvander@498
    79
}
dvander@498
    80
dvander@498
    81
void CConCmdManager::OnPluginDestroyed(IPlugin *plugin)
dvander@498
    82
{
dvander@498
    83
	CmdList *pList;
dvander@500
    84
	List<ConCmdInfo *> removed;
dvander@498
    85
	if (plugin->GetProperty("CommandList", (void **)&pList, true))
dvander@498
    86
	{
dvander@513
    87
		IPluginContext *pContext = plugin->GetBaseContext();
dvander@498
    88
		CmdList::iterator iter;
dvander@513
    89
		/* First pass!
dvander@513
    90
	 	 * Only bother if there's an actual command list on this plugin... 
dvander@513
    91
	 	 */
dvander@498
    92
		for (iter=pList->begin();
dvander@513
    93
			iter!=pList->end();
dvander@513
    94
			iter++)
dvander@498
    95
		{
dvander@498
    96
			PlCmdInfo &cmd = (*iter);
dvander@513
    97
			ConCmdInfo *pInfo = cmd.pInfo;
dvander@513
    98
dvander@513
    99
			/* Has this chain already been fully cleaned/removed? */
dvander@513
   100
			if (removed.find(pInfo) != removed.end())
dvander@498
   101
			{
dvander@513
   102
				continue;
dvander@498
   103
			}
dvander@513
   104
dvander@513
   105
			/* Remove any hooks from us on this command */
dvander@513
   106
			RemoveConCmds(pInfo->conhooks, pContext);
dvander@513
   107
			RemoveConCmds(pInfo->srvhooks, pContext);
dvander@513
   108
dvander@513
   109
			/* See if there are still hooks */
dvander@513
   110
			if (pInfo->srvhooks.size())
dvander@513
   111
			{
dvander@513
   112
				continue;
dvander@513
   113
			}
dvander@513
   114
			if (pInfo->conhooks.size())
dvander@513
   115
			{
dvander@513
   116
				continue;
dvander@513
   117
			}
dvander@513
   118
dvander@513
   119
			/* Remove the command, it should be safe now */
dvander@513
   120
			RemoveConCmd(pInfo);
dvander@513
   121
			removed.push_back(pInfo);
dvander@498
   122
		}
dvander@498
   123
		delete pList;
dvander@498
   124
	}
dvander@498
   125
}
dvander@498
   126
dvander@498
   127
void CommandCallback()
dvander@498
   128
{
dvander@498
   129
	g_ConCmds.InternalDispatch();
dvander@498
   130
}
dvander@498
   131
dvander@498
   132
void CConCmdManager::SetCommandClient(int client)
dvander@498
   133
{
dvander@498
   134
	m_CmdClient = client + 1;
dvander@498
   135
}
dvander@498
   136
dvander@500
   137
ResultType CConCmdManager::DispatchClientCommand(int client, ResultType type)
dvander@500
   138
{
dvander@500
   139
	const char *cmd = engine->Cmd_Argv(0);
dvander@500
   140
	int args = engine->Cmd_Argc() - 1;
dvander@500
   141
dvander@500
   142
	ConCmdInfo *pInfo;
dvander@500
   143
	if (sm_trie_retrieve(m_pCmds, cmd, (void **)&pInfo))
dvander@500
   144
	{
dvander@500
   145
		cell_t result = type;
dvander@513
   146
		cell_t tempres = result;
dvander@513
   147
		List<CmdHook *>::iterator iter;
dvander@513
   148
		CmdHook *pHook;
dvander@513
   149
		for (iter=pInfo->conhooks.begin();
dvander@513
   150
			 iter!=pInfo->conhooks.end();
dvander@513
   151
			 iter++)
dvander@500
   152
		{
dvander@513
   153
			pHook = (*iter);
dvander@514
   154
			if (pHook->pAdmin && !CheckAccess(client, cmd, pHook->pAdmin))
dvander@513
   155
			{
dvander@514
   156
				if (result < Pl_Handled)
dvander@514
   157
				{
dvander@514
   158
					result = Pl_Handled;
dvander@514
   159
				}
dvander@514
   160
				continue;
dvander@513
   161
			}
dvander@513
   162
			pHook->pf->PushCell(client);
dvander@513
   163
			pHook->pf->PushCell(args);
dvander@513
   164
			if (pHook->pf->Execute(&tempres) == SP_ERROR_NONE)
dvander@513
   165
			{
dvander@513
   166
				if (tempres > result)
dvander@513
   167
				{
dvander@513
   168
					result = tempres;
dvander@513
   169
				}
dvander@513
   170
				if (result == Pl_Stop)
dvander@513
   171
				{
dvander@513
   172
					break;
dvander@513
   173
				}
dvander@513
   174
			}
dvander@500
   175
		}
dvander@500
   176
		type = (ResultType)result;
dvander@500
   177
	}
dvander@500
   178
dvander@500
   179
	return type;
dvander@500
   180
}
dvander@500
   181
dvander@498
   182
void CConCmdManager::InternalDispatch()
dvander@498
   183
{
dvander@500
   184
	/**
dvander@500
   185
	 * Note: Console commands will EITHER go through IServerGameDLL::ClientCommand,
dvander@500
   186
	 * OR this dispatch.  They will NEVER go through both.
dvander@500
   187
	 * -- 
dvander@500
   188
	 * Whether or not it goes through the callback is determined by FCVAR_GAMEDLL
dvander@500
   189
	 */
dvander@498
   190
dvander@498
   191
	const char *cmd = engine->Cmd_Argv(0);
dvander@498
   192
	ConCmdInfo *pInfo;
dvander@498
   193
	if (!sm_trie_retrieve(m_pCmds, cmd, (void **)&pInfo))
dvander@498
   194
	{
dvander@498
   195
		return;
dvander@498
   196
	}
dvander@498
   197
dvander@498
   198
	cell_t result = Pl_Continue;
dvander@500
   199
	int args = engine->Cmd_Argc() - 1;
dvander@500
   200
dvander@513
   201
	List<CmdHook *>::iterator iter;
dvander@513
   202
	CmdHook *pHook;
dvander@513
   203
dvander@513
   204
	/* Execute server-only commands if viable */
dvander@513
   205
	if (m_CmdClient == 0 && pInfo->srvhooks.size())
dvander@498
   206
	{
dvander@513
   207
		cell_t tempres = result;
dvander@513
   208
		for (iter=pInfo->srvhooks.begin();
dvander@513
   209
			 iter!=pInfo->srvhooks.end();
dvander@513
   210
			 iter++)
dvander@500
   211
		{
dvander@513
   212
			pHook = (*iter);
dvander@513
   213
			pHook->pf->PushCell(args);
dvander@513
   214
			if (pHook->pf->Execute(&tempres) == SP_ERROR_NONE)
dvander@513
   215
			{
dvander@513
   216
				if (tempres > result)
dvander@513
   217
				{
dvander@513
   218
					result = tempres;
dvander@513
   219
				}
dvander@513
   220
				if (result == Pl_Stop)
dvander@513
   221
				{
dvander@513
   222
					break;
dvander@513
   223
				}
dvander@513
   224
			}
dvander@500
   225
		}
dvander@500
   226
	
dvander@500
   227
		/* Check if there's an early stop */
dvander@500
   228
		if (result >= Pl_Stop)
dvander@500
   229
		{
dvander@500
   230
			if (!pInfo->sourceMod)
dvander@500
   231
			{
dvander@500
   232
				RETURN_META(MRES_SUPERCEDE);
dvander@500
   233
			}
dvander@500
   234
			return;
dvander@500
   235
		}
dvander@500
   236
	}
dvander@500
   237
dvander@513
   238
	/* Execute console commands */
dvander@513
   239
	if (pInfo->conhooks.size())
dvander@500
   240
	{
dvander@513
   241
		cell_t tempres = result;
dvander@513
   242
		for (iter=pInfo->conhooks.begin();
dvander@513
   243
			iter!=pInfo->conhooks.end();
dvander@513
   244
			iter++)
dvander@513
   245
		{
dvander@513
   246
			pHook = (*iter);
dvander@513
   247
			if (m_CmdClient 
dvander@513
   248
				&& pHook->pAdmin
dvander@514
   249
				&& !CheckAccess(m_CmdClient, cmd, pHook->pAdmin))
dvander@513
   250
			{
dvander@514
   251
				if (result < Pl_Handled)
dvander@514
   252
				{
dvander@514
   253
					result = Pl_Handled;
dvander@514
   254
				}
dvander@514
   255
				continue;
dvander@513
   256
			}
dvander@513
   257
			pHook->pf->PushCell(m_CmdClient);
dvander@513
   258
			pHook->pf->PushCell(args);
dvander@513
   259
			if (pHook->pf->Execute(&tempres) != SP_ERROR_NONE)
dvander@513
   260
			{
dvander@513
   261
				if (tempres > result)
dvander@513
   262
				{
dvander@513
   263
					result = tempres;
dvander@513
   264
				}
dvander@513
   265
				if (result == Pl_Stop)
dvander@513
   266
				{
dvander@513
   267
					break;
dvander@513
   268
				}
dvander@513
   269
			}
dvander@513
   270
		}
dvander@498
   271
	}
dvander@498
   272
dvander@498
   273
	if (result >= Pl_Handled)
dvander@498
   274
	{
dvander@498
   275
		if (!pInfo->sourceMod)
dvander@498
   276
		{
dvander@498
   277
			RETURN_META(MRES_SUPERCEDE);
dvander@498
   278
		}
dvander@498
   279
		return;
dvander@498
   280
	}
dvander@498
   281
}
dvander@498
   282
dvander@514
   283
bool CConCmdManager::CheckAccess(int client, const char *cmd, AdminCmdInfo *pAdmin)
dvander@513
   284
{
dvander@514
   285
	FlagBits cmdflags = pAdmin->eflags;
dvander@514
   286
	if (cmdflags == 0)
dvander@514
   287
	{
dvander@514
   288
		return true;
dvander@514
   289
	}
dvander@514
   290
dvander@514
   291
	CPlayer *player = g_Players.GetPlayerByIndex(client);
dvander@514
   292
	if (!player)
dvander@514
   293
	{
dvander@514
   294
		return false;
dvander@514
   295
	}
dvander@514
   296
dvander@514
   297
	AdminId adm = player->GetAdminId();
dvander@514
   298
	if (adm != INVALID_ADMIN_ID)
dvander@514
   299
	{
dvander@514
   300
		FlagBits bits = g_Admins.GetAdminFlags(adm, Access_Effective);
dvander@514
   301
dvander@514
   302
		/* root knows all, WHOA */
dvander@514
   303
		if ((bits & ADMFLAG_ROOT) == ADMFLAG_ROOT)
dvander@514
   304
		{
dvander@514
   305
			return true;
dvander@514
   306
		}
dvander@514
   307
dvander@514
   308
		/* See if our other flags match */
dvander@514
   309
		if ((bits & cmdflags) != cmdflags)
dvander@514
   310
		{
dvander@514
   311
			return true;
dvander@514
   312
		}
dvander@514
   313
dvander@514
   314
		/* Check for overrides */
dvander@514
   315
		unsigned int groups = g_Admins.GetAdminGroupCount(adm);
dvander@514
   316
		GroupId gid;
dvander@514
   317
		OverrideRule rule;
dvander@514
   318
		bool override = false;
dvander@514
   319
		for (unsigned int i=0; i<groups; i++)
dvander@514
   320
		{
dvander@514
   321
			gid = g_Admins.GetAdminGroup(adm, i, NULL);
dvander@514
   322
			/* First get group-level override */
dvander@514
   323
			override = g_Admins.GetGroupCommandOverride(gid, cmd, Override_CommandGroup, &rule);
dvander@514
   324
			/* Now get the specific command override */
dvander@514
   325
			if (g_Admins.GetGroupCommandOverride(gid, cmd, Override_Command, &rule))
dvander@514
   326
			{
dvander@514
   327
				override = true;
dvander@514
   328
			}
dvander@514
   329
			if (override)
dvander@514
   330
			{
dvander@514
   331
				if (rule == Command_Allow)
dvander@514
   332
				{
dvander@514
   333
					return true;
dvander@514
   334
				} else if (rule == Command_Deny) {
dvander@514
   335
					break;
dvander@514
   336
				}
dvander@514
   337
			}
dvander@514
   338
		}
dvander@514
   339
	}
dvander@514
   340
dvander@514
   341
	/* If we got here, the command failed... */
dvander@514
   342
	/* :TODO: send a message to the client about this! */
dvander@514
   343
	return false;
dvander@513
   344
}
dvander@513
   345
dvander@500
   346
void CConCmdManager::AddConsoleCommand(IPluginFunction *pFunction, 
dvander@500
   347
									   const char *name, 
dvander@500
   348
									   const char *description, 
dvander@500
   349
									   int flags)
dvander@500
   350
{
dvander@500
   351
	ConCmdInfo *pInfo = AddOrFindCommand(name, description, flags);
dvander@513
   352
	CmdHook *pHook = new CmdHook();
dvander@500
   353
dvander@513
   354
	pHook->pf = pFunction;
dvander@513
   355
	if (description && description[0])
dvander@500
   356
	{
dvander@513
   357
		pHook->helptext.assign(description);
dvander@500
   358
	}
dvander@513
   359
	pInfo->conhooks.push_back(pHook);
dvander@500
   360
dvander@500
   361
	/* Add to the plugin */
dvander@500
   362
	CmdList *pList;
dvander@500
   363
	IPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pFunction->GetParentContext()->GetContext());
dvander@500
   364
	if (!pPlugin->GetProperty("CommandList", (void **)&pList))
dvander@500
   365
	{
dvander@500
   366
		pList = new CmdList();
dvander@500
   367
		pPlugin->SetProperty("CommandList", pList);
dvander@500
   368
	}
dvander@500
   369
	PlCmdInfo info;
dvander@500
   370
	info.pInfo = pInfo;
dvander@500
   371
	info.type = Cmd_Console;
dvander@513
   372
	info.pHook = pHook;
dvander@513
   373
	AddToPlCmdList(pList, info);
dvander@513
   374
}
dvander@513
   375
dvander@513
   376
bool CConCmdManager::AddAdminCommand(IPluginFunction *pFunction, 
dvander@513
   377
									 const char *name, 
dvander@513
   378
									 const char *group,
dvander@513
   379
									 int adminflags,
dvander@513
   380
									 const char *description, 
dvander@513
   381
									 int flags)
dvander@513
   382
{
dvander@513
   383
	ConCmdInfo *pInfo = AddOrFindCommand(name, description, flags);
dvander@513
   384
dvander@513
   385
	CmdHook *pHook = new CmdHook();
dvander@513
   386
	AdminCmdInfo *pAdmin = new AdminCmdInfo();
dvander@513
   387
dvander@513
   388
	pHook->pf = pFunction;
dvander@513
   389
	if (description && description[0])
dvander@513
   390
	{
dvander@513
   391
		pHook->helptext.assign(description);
dvander@513
   392
	}
dvander@513
   393
	pHook->pAdmin = pAdmin;
dvander@513
   394
dvander@513
   395
	void *object;
dvander@513
   396
	int grpid;
dvander@513
   397
	if (!sm_trie_retrieve(m_pCmdGrps, group, (void **)&object))
dvander@513
   398
	{
dvander@513
   399
		grpid = m_Strings.AddString(group);
dvander@513
   400
		sm_trie_insert(m_pCmdGrps, group, (void *)grpid);
dvander@513
   401
	} else {
dvander@513
   402
		grpid = (int)object;
dvander@513
   403
	}
dvander@513
   404
dvander@513
   405
	pAdmin->cmdGrpId = grpid;
dvander@513
   406
	pAdmin->flags = flags;
dvander@513
   407
dvander@513
   408
	/* First get the command group override, if any */
dvander@513
   409
	bool override = g_Admins.GetCommandOverride(group, 
dvander@513
   410
		Override_CommandGroup,
dvander@513
   411
		&(pAdmin->eflags));
dvander@513
   412
dvander@513
   413
	/* Next get the command override, if any */
dvander@513
   414
	if (g_Admins.GetCommandOverride(name,
dvander@513
   415
		Override_Command,
dvander@513
   416
		&(pAdmin->eflags)))
dvander@513
   417
	{
dvander@513
   418
		override = true;
dvander@513
   419
	}
dvander@513
   420
dvander@513
   421
	/* Assign normal flags if there were no overrides */
dvander@513
   422
	if (!override)
dvander@513
   423
	{
dvander@513
   424
		pAdmin->eflags = pAdmin->flags;
dvander@513
   425
	}
dvander@513
   426
dvander@513
   427
	/* Finally, add the hook */
dvander@513
   428
	pInfo->conhooks.push_back(pHook);
dvander@513
   429
dvander@513
   430
	/* Now add to the plugin */
dvander@513
   431
	CmdList *pList;
dvander@513
   432
	IPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pFunction->GetParentContext()->GetContext());
dvander@513
   433
	if (!pPlugin->GetProperty("CommandList", (void **)&pList))
dvander@513
   434
	{
dvander@513
   435
		pList = new CmdList();
dvander@513
   436
		pPlugin->SetProperty("CommandList", pList);
dvander@513
   437
	}
dvander@513
   438
	PlCmdInfo info;
dvander@513
   439
	info.pInfo = pInfo;
dvander@513
   440
	info.type = Cmd_Admin;
dvander@513
   441
	info.pHook = pHook;
dvander@513
   442
	AddToPlCmdList(pList, info);
dvander@513
   443
dvander@513
   444
	return true;
dvander@500
   445
}
dvander@500
   446
dvander@498
   447
void CConCmdManager::AddServerCommand(IPluginFunction *pFunction, 
dvander@498
   448
									  const char *name, 
dvander@498
   449
									  const char *description, 
dvander@498
   450
									  int flags)
dvander@498
   451
dvander@498
   452
{
dvander@498
   453
	ConCmdInfo *pInfo = AddOrFindCommand(name, description, flags);
dvander@513
   454
	CmdHook *pHook = new CmdHook();
dvander@498
   455
dvander@513
   456
	pHook->pf = pFunction;
dvander@513
   457
	if (description && description[0])
dvander@498
   458
	{
dvander@513
   459
		pHook->helptext.assign(description);
dvander@498
   460
	}
dvander@498
   461
dvander@513
   462
	pInfo->srvhooks.push_back(pHook);
dvander@498
   463
dvander@498
   464
	/* Add to the plugin */
dvander@498
   465
	CmdList *pList;
dvander@498
   466
	IPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pFunction->GetParentContext()->GetContext());
dvander@498
   467
	if (!pPlugin->GetProperty("CommandList", (void **)&pList))
dvander@498
   468
	{
dvander@498
   469
		pList = new CmdList();
dvander@498
   470
		pPlugin->SetProperty("CommandList", pList);
dvander@498
   471
	}
dvander@498
   472
	PlCmdInfo info;
dvander@498
   473
	info.pInfo = pInfo;
dvander@500
   474
	info.type = Cmd_Server;
dvander@513
   475
	info.pHook = pHook;
dvander@513
   476
	AddToPlCmdList(pList, info);
dvander@513
   477
}
dvander@513
   478
dvander@513
   479
void AddToPlCmdList(CmdList *pList, const PlCmdInfo &info)
dvander@513
   480
{
dvander@513
   481
	CmdList::iterator iter = pList->begin();
dvander@513
   482
	bool inserted = false;
dvander@513
   483
	const char *orig = NULL;
dvander@513
   484
dvander@513
   485
	orig = info.pInfo->pCmd->GetName();
dvander@513
   486
dvander@513
   487
	/* Insert this into the help list, SORTED alphabetically. */
dvander@513
   488
	while (iter != pList->end())
dvander@513
   489
	{
dvander@513
   490
		PlCmdInfo &obj = (*iter);
dvander@513
   491
		const char *cmd = obj.pInfo->pCmd->GetName();
dvander@513
   492
		if (strcmp(orig, cmd) < 0)
dvander@513
   493
		{
dvander@513
   494
			pList->insert(iter, info);
dvander@513
   495
			inserted = true;
dvander@513
   496
			break;
dvander@513
   497
		}
dvander@513
   498
		iter++;
dvander@513
   499
	}
dvander@513
   500
dvander@513
   501
	if (!inserted)
dvander@513
   502
	{
dvander@513
   503
		pList->push_back(info);
dvander@513
   504
	}
dvander@498
   505
}
dvander@498
   506
dvander@498
   507
void CConCmdManager::AddToCmdList(ConCmdInfo *info)
dvander@498
   508
{
dvander@498
   509
	List<ConCmdInfo *>::iterator iter = m_CmdList.begin();
dvander@498
   510
	ConCmdInfo *pInfo;
dvander@498
   511
	bool inserted = false;
dvander@503
   512
	const char *orig = NULL;
dvander@498
   513
dvander@503
   514
	orig = info->pCmd->GetName();
dvander@498
   515
dvander@498
   516
	/* Insert this into the help list, SORTED alphabetically. */
dvander@498
   517
	while (iter != m_CmdList.end())
dvander@498
   518
	{
dvander@498
   519
		const char *cmd = NULL;
dvander@498
   520
		pInfo = (*iter);
dvander@503
   521
		cmd = pInfo->pCmd->GetName();
dvander@498
   522
		if (strcmp(orig, cmd) < 0)
dvander@498
   523
		{
dvander@498
   524
			m_CmdList.insert(iter, info);
dvander@498
   525
			inserted = true;
dvander@498
   526
			break;
dvander@498
   527
		}
dvander@498
   528
		iter++;
dvander@498
   529
	}
dvander@498
   530
dvander@498
   531
	if (!inserted)
dvander@498
   532
	{
dvander@498
   533
		m_CmdList.push_back(info);
dvander@498
   534
	}
dvander@498
   535
}
dvander@498
   536
dvander@514
   537
void CConCmdManager::UpdateAdminCmdFlags(const char *cmd, OverrideType type, FlagBits bits)
dvander@514
   538
{
dvander@514
   539
	ConCmdInfo *pInfo;
dvander@514
   540
dvander@514
   541
	if (type == Override_Command)
dvander@514
   542
	{
dvander@514
   543
		if (!sm_trie_retrieve(m_pCmds, cmd, (void **)&pInfo))
dvander@514
   544
		{
dvander@514
   545
			return;
dvander@514
   546
		}
dvander@514
   547
dvander@514
   548
		List<CmdHook *>::iterator iter;
dvander@514
   549
		CmdHook *pHook;
dvander@514
   550
dvander@514
   551
		for (iter=pInfo->conhooks.begin(); iter!=pInfo->conhooks.end(); iter++)
dvander@514
   552
		{
dvander@514
   553
			pHook = (*iter);
dvander@514
   554
			if (pHook->pAdmin)
dvander@514
   555
			{
dvander@514
   556
				if (bits)
dvander@514
   557
				{
dvander@514
   558
					pHook->pAdmin->eflags = bits;
dvander@514
   559
				} else {
dvander@514
   560
					pHook->pAdmin->eflags = pHook->pAdmin->flags;
dvander@514
   561
				}
dvander@514
   562
			}
dvander@514
   563
		}
dvander@514
   564
	} else if (type == Override_CommandGroup) {
dvander@514
   565
		void *object;
dvander@514
   566
		if (!sm_trie_retrieve(m_pCmdGrps, cmd, &object))
dvander@514
   567
		{
dvander@514
   568
			return;
dvander@514
   569
		}
dvander@514
   570
		int grpid = (int)object;
dvander@514
   571
dvander@514
   572
		/* This is bad :( loop through all commands */
dvander@514
   573
		List<ConCmdInfo *>::iterator iter;
dvander@514
   574
		CmdHook *pHook;
dvander@514
   575
		for (iter=m_CmdList.begin(); iter!=m_CmdList.end(); iter++)
dvander@514
   576
		{
dvander@514
   577
			pInfo = (*iter);
dvander@514
   578
			for (List<CmdHook *>::iterator citer=pInfo->conhooks.begin();
dvander@514
   579
				 citer!=pInfo->conhooks.end();
dvander@514
   580
				 citer++)
dvander@514
   581
			{
dvander@514
   582
				pHook = (*citer);
dvander@514
   583
				if (pHook->pAdmin && pHook->pAdmin->cmdGrpId == grpid)
dvander@514
   584
				{
dvander@514
   585
					if (bits)
dvander@514
   586
					{
dvander@514
   587
						pHook->pAdmin->eflags = bits;
dvander@514
   588
					} else {
dvander@514
   589
						pHook->pAdmin->eflags = pHook->pAdmin->flags;
dvander@514
   590
					}
dvander@514
   591
				}
dvander@514
   592
			}
dvander@514
   593
		}
dvander@514
   594
	}
dvander@514
   595
}
dvander@514
   596
dvander@498
   597
void CConCmdManager::RemoveConCmd(ConCmdInfo *info)
dvander@498
   598
{
dvander@503
   599
	/* Remove console-specific information
dvander@503
   600
	 * This should always be true as of right now
dvander@503
   601
	 */
dvander@498
   602
	if (info->pCmd)
dvander@498
   603
	{
dvander@498
   604
		/* Remove from the trie */
dvander@498
   605
		sm_trie_delete(m_pCmds, info->pCmd->GetName());
dvander@498
   606
dvander@498
   607
		if (info->sourceMod)
dvander@498
   608
		{
dvander@498
   609
			/* Unlink from SourceMM */
dvander@498
   610
			g_SMAPI->UnregisterConCmdBase(g_PLAPI, info->pCmd);
dvander@498
   611
			/* Delete the command's memory */
dvander@498
   612
			char *new_help = const_cast<char *>(info->pCmd->GetHelpText());
dvander@498
   613
			char *new_name = const_cast<char *>(info->pCmd->GetName());
dvander@498
   614
			delete [] new_help;
dvander@498
   615
			delete [] new_name;
dvander@498
   616
			delete info->pCmd;
dvander@498
   617
		} else {
dvander@498
   618
			/* Remove the external hook */
dvander@498
   619
			SH_REMOVE_HOOK_STATICFUNC(ConCommand, Dispatch, info->pCmd, CommandCallback, false);
dvander@498
   620
		}
dvander@498
   621
	}
dvander@498
   622
	
dvander@498
   623
	/* Remove from list */
dvander@498
   624
	m_CmdList.remove(info);
dvander@513
   625
dvander@513
   626
	delete info;
dvander@498
   627
}
dvander@498
   628
dvander@498
   629
ConCmdInfo *CConCmdManager::AddOrFindCommand(const char *name, const char *description, int flags)
dvander@498
   630
{
dvander@498
   631
	ConCmdInfo *pInfo;
dvander@498
   632
	if (!sm_trie_retrieve(m_pCmds, name, (void **)&pInfo))
dvander@498
   633
	{
dvander@498
   634
		pInfo = new ConCmdInfo();
dvander@498
   635
		/* Find the commandopan */
dvander@498
   636
		ConCommandBase *pBase = icvar->GetCommands();
dvander@498
   637
		ConCommand *pCmd = NULL;
dvander@498
   638
		while (pBase)
dvander@498
   639
		{
dvander@498
   640
			if (pBase->IsCommand()
dvander@498
   641
				&& (strcmp(pBase->GetName(), name) == 0))
dvander@498
   642
			{
dvander@498
   643
				pCmd = (ConCommand *)pBase;
dvander@498
   644
				break;
dvander@498
   645
			}
dvander@498
   646
			pBase = const_cast<ConCommandBase *>(pBase->GetNext());
dvander@498
   647
		}
dvander@498
   648
dvander@498
   649
		if (!pCmd)
dvander@498
   650
		{
dvander@498
   651
			/* Note that we have to duplicate because the source might not be 
dvander@498
   652
			 * a static string, and these expect static memory.
dvander@498
   653
			 */
dvander@498
   654
			if (!description)
dvander@498
   655
			{
dvander@498
   656
				description = "";
dvander@498
   657
			}
dvander@498
   658
			char *new_name = sm_strdup(name);
dvander@498
   659
			char *new_help = sm_strdup(description);
dvander@498
   660
			pCmd = new ConCommand(new_name, CommandCallback, new_help, flags);
dvander@498
   661
			pInfo->sourceMod = true;
dvander@498
   662
		} else {
dvander@498
   663
			SH_ADD_HOOK_STATICFUNC(ConCommand, Dispatch, pCmd, CommandCallback, false);
dvander@498
   664
		}
dvander@498
   665
dvander@498
   666
		pInfo->pCmd = pCmd;
dvander@498
   667
dvander@498
   668
		sm_trie_insert(m_pCmds, name, pInfo);
dvander@498
   669
		AddToCmdList(pInfo);
dvander@498
   670
	}
dvander@498
   671
dvander@498
   672
	return pInfo;
dvander@498
   673
}
dvander@498
   674
dvander@498
   675
void CConCmdManager::OnRootConsoleCommand(const char *command, unsigned int argcount)
dvander@498
   676
{
dvander@499
   677
	if (argcount >= 3)
dvander@499
   678
	{
dvander@499
   679
		const char *text = engine->Cmd_Argv(2);
dvander@499
   680
		int id = atoi(text);
dvander@499
   681
		CPlugin *pPlugin = g_PluginSys.GetPluginByOrder(id);
dvander@499
   682
dvander@499
   683
		if (!pPlugin)
dvander@499
   684
		{
dvander@499
   685
			g_RootMenu.ConsolePrint("[SM] Plugin index %d not found.", id);
dvander@499
   686
			return;
dvander@499
   687
		}
dvander@499
   688
dvander@499
   689
		CmdList *pList;
dvander@499
   690
		if (!pPlugin->GetProperty("CommandList", (void **)&pList))
dvander@499
   691
		{
dvander@499
   692
			g_RootMenu.ConsolePrint("[SM] No commands found for %s", pPlugin->GetFilename());
dvander@499
   693
			return;
dvander@499
   694
		}
dvander@499
   695
		if (!pList->size())
dvander@499
   696
		{
dvander@499
   697
			g_RootMenu.ConsolePrint("[SM] No commands found for %s", pPlugin->GetFilename());
dvander@499
   698
			return;
dvander@499
   699
		}
dvander@499
   700
dvander@499
   701
		CmdList::iterator iter;
dvander@499
   702
		const char *type = NULL;
dvander@499
   703
		const char *name;
dvander@499
   704
		const char *help;
dvander@499
   705
		g_RootMenu.ConsolePrint(" %-17.16s %-8.7s %s", "[Name]", "[Type]", "[Help]");
dvander@499
   706
		for (iter=pList->begin();
dvander@499
   707
			 iter!=pList->end();
dvander@499
   708
			 iter++)
dvander@499
   709
		{
dvander@499
   710
			PlCmdInfo &cmd = (*iter);
dvander@499
   711
			if (cmd.type == Cmd_Server)
dvander@499
   712
			{
dvander@499
   713
				type = "server";
dvander@499
   714
			} else if (cmd.type == Cmd_Console) {
dvander@499
   715
				type = "console";
dvander@513
   716
			} else if (cmd.type == Cmd_Admin) {
dvander@513
   717
				type = "admin";
dvander@499
   718
			}
dvander@499
   719
			name = cmd.pInfo->pCmd->GetName();
dvander@513
   720
			if (cmd.pHook->helptext.size())
dvander@513
   721
			{
dvander@513
   722
				help = cmd.pHook->helptext.c_str();
dvander@513
   723
			} else {
dvander@513
   724
				help = cmd.pInfo->pCmd->GetHelpText();
dvander@513
   725
			}
dvander@500
   726
			g_RootMenu.ConsolePrint(" %-17.16s %-12.11s %s", name, type, help);		
dvander@499
   727
		}
dvander@499
   728
dvander@499
   729
		return;
dvander@499
   730
	}
dvander@499
   731
dvander@499
   732
	g_RootMenu.ConsolePrint("[SM] Usage: sm cmds <plugin #>");
dvander@498
   733
}