3 * ===============================================================
4 * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
5 * ===============================================================
7 * This file is not open source and may not be copied without explicit
8 * written permission of AlliedModders LLC. This file may not be redistributed
9 * in whole or significant part.
10 * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
15 #include "sm_globals.h"
16 #include "HalfLife2.h"
17 #include "sourcemm_api.h"
18 #include "HandleSys.h"
19 #include "ConVarManager.h"
20 #include "ConCmdManager.h"
21 #include "PluginSys.h"
22 #include "sm_stringutil.h"
23 #include "PlayerManager.h"
24 #include "ChatTriggers.h"
25 #include <inetchannel.h>
28 #define NET_SETCONVAR 5
32 ConVarBound_Upper = 0,
36 HandleType_t hCmdIterType = 0;
41 List<ConCmdInfo *>::iterator iter;
44 class ConsoleHelpers :
46 public IHandleTypeDispatch
49 virtual void OnSourceModAllInitialized()
52 g_HandleSys.InitAccessDefaults(NULL, &access);
53 access.access[HandleAccess_Clone] = HANDLE_RESTRICT_OWNER | HANDLE_RESTRICT_IDENTITY;
55 hCmdIterType = g_HandleSys.CreateType(NULL, this, 0, NULL, &access, g_pCoreIdent, NULL);
57 virtual void OnHandleDestroy(HandleType_t type, void *object)
59 GlobCmdIter *iter = (GlobCmdIter *)object;
64 static void ReplicateConVar(ConVar *pConVar)
66 int maxClients = g_Players.GetMaxClients();
69 bf_write buffer(data, sizeof(data));
71 buffer.WriteUBitLong(NET_SETCONVAR, 5);
73 buffer.WriteString(pConVar->GetName());
74 buffer.WriteString(pConVar->GetString());
76 for (int i = 1; i <= maxClients; i++)
78 CPlayer *pPlayer = g_Players.GetPlayerByIndex(i);
80 if (pPlayer && pPlayer->IsInGame() && !pPlayer->IsFakeClient())
82 INetChannel *netchan = static_cast<INetChannel *>(engine->GetPlayerNetInfo(i));
83 netchan->SendData(buffer);
88 static void NotifyConVar(ConVar *pConVar)
90 IGameEvent *pEvent = gameevents->CreateEvent("server_cvar");
91 pEvent->SetString("cvarname", pConVar->GetName());
92 if (pConVar->IsBitSet(FCVAR_PROTECTED))
94 pEvent->SetString("cvarvalue", "***PROTECTED***");
96 pEvent->SetString("cvarvalue", pConVar->GetString());
99 gameevents->FireEvent(pEvent);
102 static cell_t sm_CreateConVar(IPluginContext *pContext, const cell_t *params)
104 char *name, *defaultVal, *helpText;
106 pContext->LocalToString(params[1], &name);
108 // While the engine seems to accept a blank convar name, it causes a crash upon server quit
109 if (name == NULL || strcmp(name, "") == 0)
111 return pContext->ThrowNativeError("Convar with blank name is not permitted");
114 pContext->LocalToString(params[2], &defaultVal);
115 pContext->LocalToString(params[3], &helpText);
117 bool hasMin = params[5] ? true : false;
118 bool hasMax = params[7] ? true : false;
119 float min = sp_ctof(params[6]);
120 float max = sp_ctof(params[8]);
122 Handle_t hndl = g_ConVarManager.CreateConVar(pContext, name, defaultVal, helpText, params[4], hasMin, min, hasMax, max);
124 if (hndl == BAD_HANDLE)
126 return pContext->ThrowNativeError("Convar \"%s\" was not created. A console command with the same name already exists.", name);
132 static cell_t sm_FindConVar(IPluginContext *pContext, const cell_t *params)
136 pContext->LocalToString(params[1], &name);
138 return g_ConVarManager.FindConVar(name);
141 static cell_t sm_HookConVarChange(IPluginContext *pContext, const cell_t *params)
143 Handle_t hndl = static_cast<Handle_t>(params[1]);
147 if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
150 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
153 IPluginFunction *pFunction = pContext->GetFunctionById(params[2]);
157 return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
160 g_ConVarManager.HookConVarChange(pConVar, pFunction);
165 static cell_t sm_UnhookConVarChange(IPluginContext *pContext, const cell_t *params)
167 Handle_t hndl = static_cast<Handle_t>(params[1]);
171 if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
174 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
177 IPluginFunction *pFunction = pContext->GetFunctionById(params[2]);
181 return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
184 g_ConVarManager.UnhookConVarChange(pConVar, pFunction);
189 static cell_t sm_GetConVarBool(IPluginContext *pContext, const cell_t *params)
191 Handle_t hndl = static_cast<Handle_t>(params[1]);
195 if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
198 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
201 return pConVar->GetBool();
204 static cell_t sm_GetConVarInt(IPluginContext *pContext, const cell_t *params)
206 Handle_t hndl = static_cast<Handle_t>(params[1]);
210 if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
213 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
216 return pConVar->GetInt();
219 /* This handles both SetConVarBool() and SetConVarInt() */
220 static cell_t sm_SetConVarNum(IPluginContext *pContext, const cell_t *params)
222 Handle_t hndl = static_cast<Handle_t>(params[1]);
226 if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
229 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
232 pConVar->SetValue(params[2]);
234 /* Should we replicate it? */
235 if (params[3] && pConVar->IsBitSet(FCVAR_REPLICATED))
237 ReplicateConVar(pConVar);
240 /* Should we notify clients? */
241 if (params[4] && pConVar->IsBitSet(FCVAR_NOTIFY))
243 NotifyConVar(pConVar);
249 static cell_t sm_GetConVarFloat(IPluginContext *pContext, const cell_t *params)
251 Handle_t hndl = static_cast<Handle_t>(params[1]);
255 if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
258 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
261 float value = pConVar->GetFloat();
263 return sp_ftoc(value);
266 static cell_t sm_SetConVarFloat(IPluginContext *pContext, const cell_t *params)
268 Handle_t hndl = static_cast<Handle_t>(params[1]);
272 if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
275 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
278 float value = sp_ctof(params[2]);
279 pConVar->SetValue(value);
281 /* Should we replicate it? */
282 if (params[3] && pConVar->IsBitSet(FCVAR_REPLICATED))
284 ReplicateConVar(pConVar);
287 /* Should we notify clients? */
288 if (params[4] && pConVar->IsBitSet(FCVAR_NOTIFY))
290 NotifyConVar(pConVar);
296 static cell_t sm_GetConVarString(IPluginContext *pContext, const cell_t *params)
298 Handle_t hndl = static_cast<Handle_t>(params[1]);
302 if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
305 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
308 pContext->StringToLocalUTF8(params[2], params[3], pConVar->GetString(), NULL);
313 static cell_t sm_SetConVarString(IPluginContext *pContext, const cell_t *params)
315 Handle_t hndl = static_cast<Handle_t>(params[1]);
319 if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
322 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
326 pContext->LocalToString(params[2], &value);
328 pConVar->SetValue(value);
330 /* Should we replicate it? */
331 if (params[3] && pConVar->IsBitSet(FCVAR_REPLICATED))
333 ReplicateConVar(pConVar);
336 /* Should we notify clients? */
337 if (params[4] && pConVar->IsBitSet(FCVAR_NOTIFY))
339 NotifyConVar(pConVar);
345 static cell_t sm_GetConVarFlags(IPluginContext *pContext, const cell_t *params)
347 Handle_t hndl = static_cast<Handle_t>(params[1]);
351 if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
354 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
357 return pConVar->GetFlags();
360 static cell_t sm_SetConVarFlags(IPluginContext *pContext, const cell_t *params)
362 Handle_t hndl = static_cast<Handle_t>(params[1]);
366 if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
369 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
372 pConVar->SetFlags(params[2]);
377 static cell_t sm_GetConVarBounds(IPluginContext *pContext, const cell_t *params)
379 Handle_t hndl = static_cast<Handle_t>(params[1]);
383 if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
386 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
395 case ConVarBound_Upper:
396 hasBound = pConVar->GetMax(bound);
398 case ConVarBound_Lower:
399 hasBound = pConVar->GetMin(bound);
402 return pContext->ThrowNativeError("Invalid ConVarBounds value %d");
405 pContext->LocalToPhysAddr(params[3], &addr);
406 *addr = sp_ftoc(bound);
411 static cell_t sm_SetConVarBounds(IPluginContext *pContext, const cell_t *params)
413 Handle_t hndl = static_cast<Handle_t>(params[1]);
417 if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
420 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
425 case ConVarBound_Upper:
426 pConVar->SetMax(params[3] ? true : false, sp_ctof(params[4]));
428 case ConVarBound_Lower:
429 pConVar->SetMin(params[3] ? true : false, sp_ctof(params[4]));
432 return pContext->ThrowNativeError("Invalid ConVarBounds value %d");
438 static cell_t sm_GetConVarName(IPluginContext *pContext, const cell_t *params)
440 Handle_t hndl = static_cast<Handle_t>(params[1]);
444 if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
447 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
450 pContext->StringToLocalUTF8(params[2], params[3], pConVar->GetName(), NULL);
455 static cell_t sm_ResetConVar(IPluginContext *pContext, const cell_t *params)
457 Handle_t hndl = static_cast<Handle_t>(params[1]);
461 if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
464 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
472 static bool s_QueryAlreadyWarned = false;
474 static cell_t sm_QueryClientConVar(IPluginContext *pContext, const cell_t *params)
478 IPluginFunction *pCallback;
480 if (g_IsOriginalEngine)
482 if (!s_QueryAlreadyWarned)
484 s_QueryAlreadyWarned = true;
485 return pContext->ThrowNativeError("Game does not support client convar querying (one time warning)");
491 pPlayer = g_Players.GetPlayerByIndex(params[1]);
495 return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
498 if (!pPlayer->IsConnected())
500 return pContext->ThrowNativeError("Client %d is not connected", params[1]);
503 /* Trying a query on a bot results in callback not be fired, so don't bother */
504 if (pPlayer->IsFakeClient())
509 pContext->LocalToString(params[2], &name);
510 pCallback = pContext->GetFunctionById(params[3]);
514 return pContext->ThrowNativeError("Invalid function id (%X)", params[3]);
517 return g_ConVarManager.QueryClientConVar(pPlayer->GetEdict(), name, pCallback, params[4]);
520 static cell_t sm_RegServerCmd(IPluginContext *pContext, const cell_t *params)
523 IPluginFunction *pFunction;
525 pContext->LocalToString(params[1], &name);
526 pContext->LocalToString(params[3], &help);
527 pFunction = pContext->GetFunctionById(params[2]);
531 return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
534 if (!g_ConCmds.AddServerCommand(pFunction, name, help, params[4]))
536 return pContext->ThrowNativeError("Command \"%s\" could not be created. A convar with the same name already exists.", name);
542 static cell_t sm_RegConsoleCmd(IPluginContext *pContext, const cell_t *params)
545 IPluginFunction *pFunction;
547 pContext->LocalToString(params[1], &name);
548 pContext->LocalToString(params[3], &help);
549 pFunction = pContext->GetFunctionById(params[2]);
553 return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
556 if (!g_ConCmds.AddConsoleCommand(pFunction, name, help, params[4]))
558 return pContext->ThrowNativeError("Command \"%s\" could not be created. A convar with the same name already exists.", name);
564 static cell_t sm_RegAdminCmd(IPluginContext *pContext, const cell_t *params)
568 IPluginFunction *pFunction;
569 FlagBits flags = params[3];
570 int cmdflags = params[6];
572 pContext->LocalToString(params[1], &name);
573 pContext->LocalToString(params[4], &help);
574 pContext->LocalToString(params[5], (char **)&group);
575 pFunction = pContext->GetFunctionById(params[2]);
577 if (group[0] == '\0')
579 CPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pContext->GetContext());
580 group = pPlugin->GetFilename();
585 return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
588 if (!g_ConCmds.AddAdminCommand(pFunction, name, group, flags, help, cmdflags))
590 return pContext->ThrowNativeError("Command \"%s\" could not be created. A convar with the same name already exists.", name);
596 static cell_t sm_GetCmdArgs(IPluginContext *pContext, const cell_t *params)
598 return engine->Cmd_Argc() - 1;
601 static cell_t sm_GetCmdArg(IPluginContext *pContext, const cell_t *params)
603 const char *arg = engine->Cmd_Argv(params[1]);
605 pContext->StringToLocalUTF8(params[2], params[3], arg, NULL);
610 static cell_t sm_GetCmdArgString(IPluginContext *pContext, const cell_t *params)
612 const char *args = engine->Cmd_Args();
619 pContext->StringToLocalUTF8(params[1], params[2], args, NULL);
624 static cell_t sm_PrintToServer(IPluginContext *pCtx, const cell_t *params)
630 pCtx->LocalToString(params[1], &fmt);
631 size_t res = atcprintf(buffer, sizeof(buffer)-2, fmt, pCtx, params, &arg);
633 buffer[res++] = '\n';
636 META_CONPRINT(buffer);
641 static cell_t sm_PrintToConsole(IPluginContext *pCtx, const cell_t *params)
643 int index = params[1];
644 if ((index < 0) || (index > g_Players.GetMaxClients()))
646 return pCtx->ThrowNativeError("Client index %d is invalid", index);
649 CPlayer *pPlayer = NULL;
652 pPlayer = g_Players.GetPlayerByIndex(index);
653 if (!pPlayer->IsInGame())
655 return pCtx->ThrowNativeError("Client %d is not in game", index);
658 /* Silent fail on bots, engine will crash */
659 if (pPlayer->IsFakeClient())
669 pCtx->LocalToString(params[2], &fmt);
670 size_t res = atcprintf(buffer, sizeof(buffer)-2, fmt, pCtx, params, &arg);
672 buffer[res++] = '\n';
677 engine->ClientPrintf(pPlayer->GetEdict(), buffer);
679 META_CONPRINT(buffer);
685 static cell_t sm_ServerCommand(IPluginContext *pContext, const cell_t *params)
688 size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 1);
690 g_SourceMod.SetGlobalTarget(LANG_SERVER);
692 /* One byte for null terminator, one for newline */
693 buffer[len++] = '\n';
696 engine->ServerCommand(buffer);
701 static cell_t sm_InsertServerCommand(IPluginContext *pContext, const cell_t *params)
704 size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 1);
706 g_SourceMod.SetGlobalTarget(LANG_SERVER);
708 /* One byte for null terminator, one for newline */
709 buffer[len++] = '\n';
712 engine->InsertServerCommand(buffer);
717 static cell_t sm_ServerExecute(IPluginContext *pContext, const cell_t *params)
719 engine->ServerExecute();
724 static cell_t sm_ClientCommand(IPluginContext *pContext, const cell_t *params)
726 CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
730 return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
733 if (!pPlayer->IsConnected())
735 return pContext->ThrowNativeError("Client %d is not connected", params[1]);
738 g_SourceMod.SetGlobalTarget(params[1]);
741 g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
743 engine->ClientCommand(pPlayer->GetEdict(), "%s", buffer);
749 static cell_t FakeClientCommand(IPluginContext *pContext, const cell_t *params)
751 CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
755 return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
758 if (!pPlayer->IsConnected())
760 return pContext->ThrowNativeError("Client %d is not connected", params[1]);
764 g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
766 unsigned int old = g_ChatTriggers.SetReplyTo(SM_REPLY_CONSOLE);
767 serverpluginhelpers->ClientCommand(pPlayer->GetEdict(), buffer);
768 g_ChatTriggers.SetReplyTo(old);
773 static cell_t ReplyToCommand(IPluginContext *pContext, const cell_t *params)
775 g_SourceMod.SetGlobalTarget(params[1]);
777 /* Build the format string */
779 size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 2);
781 /* If we're printing to the server, shortcut out */
785 buffer[len++] = '\n';
787 META_CONPRINT(buffer);
791 CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
795 return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
798 if (!pPlayer->IsConnected())
800 return pContext->ThrowNativeError("Client %d is not connected", params[1]);
803 g_SourceMod.SetGlobalTarget(params[1]);
805 unsigned int replyto = g_ChatTriggers.GetReplyTo();
806 if (replyto == SM_REPLY_CONSOLE)
808 buffer[len++] = '\n';
810 engine->ClientPrintf(pPlayer->GetEdict(), buffer);
811 } else if (replyto == SM_REPLY_CHAT) {
817 g_HL2.TextMsg(params[1], HUD_PRINTTALK, buffer);
823 static cell_t GetCmdReplyTarget(IPluginContext *pContext, const cell_t *params)
825 return g_ChatTriggers.GetReplyTo();
828 static cell_t SetCmdReplyTarget(IPluginContext *pContext, const cell_t *params)
830 return g_ChatTriggers.SetReplyTo(params[1]);
833 static cell_t GetCommandIterator(IPluginContext *pContext, const cell_t *params)
835 GlobCmdIter *iter = new GlobCmdIter;
836 iter->started = false;
838 Handle_t hndl = g_HandleSys.CreateHandle(hCmdIterType, iter, pContext->GetIdentity(), g_pCoreIdent, NULL);
839 if (hndl == BAD_HANDLE)
847 static cell_t ReadCommandIterator(IPluginContext *pContext, const cell_t *params)
851 HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
853 if ((err = g_HandleSys.ReadHandle(params[1], hCmdIterType, &sec, (void **)&iter))
856 return pContext->ThrowNativeError("Invalid GlobCmdIter Handle %x", params[1]);
859 const List<ConCmdInfo *> &cmds = g_ConCmds.GetCommandList();
863 iter->iter = cmds.begin();
864 iter->started = true;
867 while (iter->iter != cmds.end()
868 && !(*(iter->iter))->sourceMod)
873 if (iter->iter == cmds.end())
878 ConCmdInfo *pInfo = (*(iter->iter));
880 pContext->StringToLocalUTF8(params[2], params[3], pInfo->pCmd->GetName(), NULL);
881 pContext->StringToLocalUTF8(params[5], params[6], pInfo->pCmd->GetHelpText(), NULL);
884 pContext->LocalToPhysAddr(params[4], &addr);
885 *addr = pInfo->admin.eflags;
892 static cell_t CheckCommandAccess(IPluginContext *pContext, const cell_t *params)
900 pContext->LocalToString(params[2], &cmd);
902 return g_ConCmds.CheckCommandAccess(params[1], cmd, params[3]) ? 1 : 0;
905 REGISTER_NATIVES(consoleNatives)
907 {"CreateConVar", sm_CreateConVar},
908 {"FindConVar", sm_FindConVar},
909 {"HookConVarChange", sm_HookConVarChange},
910 {"UnhookConVarChange", sm_UnhookConVarChange},
911 {"GetConVarBool", sm_GetConVarBool},
912 {"SetConVarBool", sm_SetConVarNum},
913 {"GetConVarInt", sm_GetConVarInt},
914 {"SetConVarInt", sm_SetConVarNum},
915 {"GetConVarFloat", sm_GetConVarFloat},
916 {"SetConVarFloat", sm_SetConVarFloat},
917 {"GetConVarString", sm_GetConVarString},
918 {"SetConVarString", sm_SetConVarString},
919 {"GetConVarFlags", sm_GetConVarFlags},
920 {"SetConVarFlags", sm_SetConVarFlags},
921 {"GetConVarName", sm_GetConVarName},
922 {"GetConVarBounds", sm_GetConVarBounds},
923 {"SetConVarBounds", sm_SetConVarBounds},
924 {"ResetConVar", sm_ResetConVar},
925 {"QueryClientConVar", sm_QueryClientConVar},
926 {"RegServerCmd", sm_RegServerCmd},
927 {"RegConsoleCmd", sm_RegConsoleCmd},
928 {"GetCmdArgString", sm_GetCmdArgString},
929 {"GetCmdArgs", sm_GetCmdArgs},
930 {"GetCmdArg", sm_GetCmdArg},
931 {"PrintToServer", sm_PrintToServer},
932 {"PrintToConsole", sm_PrintToConsole},
933 {"RegAdminCmd", sm_RegAdminCmd},
934 {"ServerCommand", sm_ServerCommand},
935 {"InsertServerCommand", sm_InsertServerCommand},
936 {"ServerExecute", sm_ServerExecute},
937 {"ClientCommand", sm_ClientCommand},
938 {"FakeClientCommand", FakeClientCommand},
939 {"ReplyToCommand", ReplyToCommand},
940 {"GetCmdReplySource", GetCmdReplyTarget},
941 {"SetCmdReplySource", SetCmdReplyTarget},
942 {"GetCommandIterator", GetCommandIterator},
943 {"ReadCommandIterator", ReadCommandIterator},
944 {"CheckCommandAccess", CheckCommandAccess},