core/CoreConfig.cpp
author Scott Ehlert <ds@alliedmods.net>
Wed Jun 11 08:07:17 2008 +0000 (2008-06-11)
changeset 2112 2a83a521287c
parent 2065 e2e5445a2f9b
child 2166 b2594457bad1
permissions -rw-r--r--
All natives that use a recipient filter now actually validate the clients passed to them.
This includes StartMessage(), StartMessageEx() from Core as well as EmitSound(), EmitSentence(), and TE_Send() from SDKTools

(Warning: This may potentially cause a minor compatibility problem with plugins that don't check client validity before passing to these natives)
     1 /**
     2  * vim: set ts=4 :
     3  * =============================================================================
     4  * SourceMod
     5  * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
     6  * =============================================================================
     7  *
     8  * This program is free software; you can redistribute it and/or modify it under
     9  * the terms of the GNU General Public License, version 3.0, as published by the
    10  * Free Software Foundation.
    11  * 
    12  * This program is distributed in the hope that it will be useful, but WITHOUT
    13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    14  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    15  * details.
    16  *
    17  * You should have received a copy of the GNU General Public License along with
    18  * this program.  If not, see <http://www.gnu.org/licenses/>.
    19  *
    20  * As a special exception, AlliedModders LLC gives you permission to link the
    21  * code of this program (as well as its derivative works) to "Half-Life 2," the
    22  * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
    23  * by the Valve Corporation.  You must obey the GNU General Public License in
    24  * all respects for all other code used.  Additionally, AlliedModders LLC grants
    25  * this exception to all derivative works.  AlliedModders LLC defines further
    26  * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
    27  * or <http://www.sourcemod.net/license.php>.
    28  *
    29  * Version: $Id$
    30  */
    31 
    32 #include <ITextParsers.h>
    33 #include "CoreConfig.h"
    34 #include "sourcemod.h"
    35 #include "sourcemm_api.h"
    36 #include "sm_srvcmds.h"
    37 #include "sm_version.h"
    38 #include "sm_stringutil.h"
    39 #include "LibrarySys.h"
    40 #include "Logger.h"
    41 #include "PluginSys.h"
    42 #include "ForwardSys.h"
    43 
    44 #ifdef PLATFORM_WINDOWS
    45 ConVar sm_corecfgfile("sm_corecfgfile", "addons\\sourcemod\\configs\\core.cfg", 0, "SourceMod core configuration file");
    46 #elif defined PLATFORM_LINUX
    47 ConVar sm_corecfgfile("sm_corecfgfile", "addons/sourcemod/configs/core.cfg", 0, "SourceMod core configuration file");
    48 #endif
    49 
    50 IForward *g_pOnServerCfg = NULL;
    51 IForward *g_pOnConfigsExecuted = NULL;
    52 IForward *g_pOnAutoConfigsBuffered = NULL;
    53 CoreConfig g_CoreConfig;
    54 bool g_bConfigsExecd = false;
    55 
    56 void CoreConfig::OnSourceModAllInitialized()
    57 {
    58 	g_RootMenu.AddRootConsoleCommand("config", "Set core configuration options", this);
    59 	g_pOnServerCfg = g_Forwards.CreateForward("OnServerCfg", ET_Ignore, 0, NULL);
    60 	g_pOnConfigsExecuted = g_Forwards.CreateForward("OnConfigsExecuted", ET_Ignore, 0, NULL);
    61 	g_pOnAutoConfigsBuffered = g_Forwards.CreateForward("OnAutoConfigsBuffered", ET_Ignore, 0, NULL);
    62 }
    63 
    64 void CoreConfig::OnSourceModShutdown()
    65 {
    66 	g_RootMenu.RemoveRootConsoleCommand("config", this);
    67 	g_Forwards.ReleaseForward(g_pOnServerCfg);
    68 	g_Forwards.ReleaseForward(g_pOnConfigsExecuted);
    69 	g_Forwards.ReleaseForward(g_pOnAutoConfigsBuffered);
    70 }
    71 
    72 void CoreConfig::OnSourceModLevelChange(const char *mapName)
    73 {
    74 	g_bConfigsExecd = false;
    75 }
    76 
    77 void CoreConfig::OnRootConsoleCommand(const char *cmdname, const CCommand &command)
    78 {
    79 	int argcount = command.ArgC();
    80 	if (argcount >= 4)
    81 	{
    82 		const char *option = command.Arg(2);
    83 		const char *value = command.Arg(3);
    84 
    85 		char error[255];
    86 
    87 		ConfigResult res = SetConfigOption(option, value, ConfigSource_Console, error, sizeof(error));
    88 
    89 		if (res == ConfigResult_Reject)
    90 		{
    91 			g_RootMenu.ConsolePrint("[SM] Could not set config option \"%s\" to \"%s\" (%s)", option, value, error);
    92 		} else if (res == ConfigResult_Ignore) {
    93 			g_RootMenu.ConsolePrint("[SM] No such config option \"%s\" exists.", option);
    94 		} else {
    95 			g_RootMenu.ConsolePrint("Config option \"%s\" successfully set to \"%s.\"", option, value);
    96 		}
    97 
    98 		return;
    99 	}
   100 
   101 	g_RootMenu.ConsolePrint("[SM] Usage: sm config <option> <value>");
   102 }
   103 
   104 void CoreConfig::Initialize()
   105 {
   106 	SMCError err;
   107 	char filePath[PLATFORM_MAX_PATH];
   108 
   109 	/* Try to get command line value of core config convar */
   110 	const char *corecfg = icvar->GetCommandLineValue("sm_corecfgfile");
   111 
   112 	/* If sm_corecfgfile not specified on command line, use default value */
   113 	if (!corecfg)
   114 	{
   115 		corecfg = sm_corecfgfile.GetDefault();
   116 	}
   117 
   118 	/* Format path to config file */
   119 	g_LibSys.PathFormat(filePath, sizeof(filePath), "%s/%s", g_SourceMod.GetGamePath(), corecfg);
   120 
   121 	/* Parse config file */
   122 	if ((err=textparsers->ParseFile_SMC(filePath, this, NULL)) != SMCError_Okay)
   123 	{
   124  		/* :TODO: This won't actually log or print anything :( - So fix that somehow */
   125 		const char *error = textparsers->GetSMCErrorString(err);
   126 		g_Logger.LogFatal("[SM] Error encountered parsing core config file: %s", error ? error : "");
   127 	}
   128 }
   129 
   130 SMCResult CoreConfig::ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value)
   131 {
   132 	char error[255];
   133 	ConfigResult err = SetConfigOption(key, value, ConfigSource_File, error, sizeof(error));
   134 
   135 	if (err == ConfigResult_Reject)
   136 	{
   137 		/* This is a fatal error */
   138 		g_Logger.LogFatal("Config error (key: %s) (value: %s) %s", key, value, error);
   139 	}
   140 
   141 	return SMCResult_Continue;
   142 }
   143 
   144 ConfigResult CoreConfig::SetConfigOption(const char *option, const char *value, ConfigSource source, char *error, size_t maxlength)
   145 {
   146 	ConfigResult result;
   147 
   148 	/* Notify! */
   149 	SMGlobalClass *pBase = SMGlobalClass::head;
   150 	while (pBase)
   151 	{
   152 		if ((result = pBase->OnSourceModConfigChanged(option, value, source, error, maxlength)) != ConfigResult_Ignore)
   153 		{
   154 			return result;
   155 		}
   156 		pBase = pBase->m_pGlobalClassNext;
   157 	}
   158 
   159 	return ConfigResult_Ignore;
   160 }
   161 
   162 bool SM_AreConfigsExecuted()
   163 {
   164 	return g_bConfigsExecd;
   165 }
   166 
   167 inline bool IsPathSepChar(char c)
   168 {
   169 #if defined PLATFORM_WINDOWS
   170 	return (c == '\\' || c == '/');
   171 #elif defined PLATFORM_LINUX
   172 	return (c == '/');
   173 #endif
   174 }
   175 
   176 bool SM_ExecuteConfig(CPlugin *pl, AutoConfig *cfg, bool can_create)
   177 {
   178 	bool will_create = false;
   179 	
   180 	/* See if we should be creating */
   181 	if (can_create && cfg->create)
   182 	{
   183 		will_create = true;
   184 		
   185 		/* If the folder does not exist, attempt to create it.  
   186 		 * We're awfully nice.
   187 		 */
   188 		const char *folder = cfg->folder.c_str();
   189 		char path[PLATFORM_MAX_PATH];
   190 		char build[PLATFORM_MAX_PATH];
   191 
   192 		g_SourceMod.BuildPath(Path_Game, path, sizeof(path), "cfg/%s", folder);
   193 
   194 		if (!g_LibSys.IsPathDirectory(path))
   195 		{
   196 			char *cur_ptr = path;
   197 			size_t len;
   198 			
   199 			g_LibSys.PathFormat(path, sizeof(path), "%s", folder);
   200 			len = g_SourceMod.BuildPath(Path_Game, build, sizeof(build), "cfg");
   201 
   202 			do
   203 			{
   204 				/* Find next suitable path */
   205 				char *next_ptr = cur_ptr;
   206 				while (*next_ptr != '\0')
   207 				{
   208 					if (IsPathSepChar(*next_ptr))
   209 					{
   210 						*next_ptr = '\0';
   211 						next_ptr++;
   212 						break;
   213 					}
   214 					next_ptr++;
   215 				}
   216 				if (*next_ptr == '\0')
   217 				{
   218 					next_ptr = NULL;
   219 				}
   220 				len += g_LibSys.PathFormat(&build[len], 
   221 					sizeof(build)-len,
   222 					"/%s",
   223 					cur_ptr);
   224 				if (!g_LibSys.CreateFolder(build))
   225 				{
   226 					break;
   227 				}
   228 				cur_ptr = next_ptr;
   229 			} while (cur_ptr);
   230 		}
   231 	}
   232 
   233 	/* Check if the file exists. */
   234 	char file[PLATFORM_MAX_PATH];
   235 	char local[PLATFORM_MAX_PATH];
   236 
   237 	if (cfg->folder.size())
   238 	{
   239 		g_LibSys.PathFormat(local, 
   240 			sizeof(local), 
   241 			"%s/%s.cfg",
   242 			cfg->folder.c_str(),
   243 			cfg->autocfg.c_str());
   244 	} else {
   245 		g_LibSys.PathFormat(local,
   246 			sizeof(local),
   247 			"%s.cfg",
   248 			cfg->autocfg.c_str());
   249 	}
   250 	
   251 	g_SourceMod.BuildPath(Path_Game, file, sizeof(file), "cfg/%s", local);
   252 
   253 	bool file_exists = g_LibSys.IsPathFile(file);
   254 	if (!file_exists && will_create)
   255 	{
   256 		List<const ConVar *> *convars = NULL;
   257 		if (pl->GetProperty("ConVarList", (void **)&convars, false) && convars)
   258 		{
   259 			/* Attempt to create it */
   260 			FILE *fp = fopen(file, "wt");
   261 			if (fp)
   262 			{
   263 				fprintf(fp, "// This file was auto-generated by SourceMod (v%s)\n", SVN_FULL_VERSION);
   264 				fprintf(fp, "// ConVars for plugin \"%s\"\n", pl->GetFilename());
   265 				fprintf(fp, "\n\n");
   266 
   267 				List<const ConVar *>::iterator iter;
   268 				float x;
   269 				for (iter = convars->begin(); iter != convars->end(); iter++)
   270 				{
   271 					const ConVar *cvar = (*iter);
   272 
   273 					if ((cvar->GetFlags() & FCVAR_DONTRECORD) == FCVAR_DONTRECORD)
   274 					{
   275 						continue;
   276 					}
   277 
   278 					char descr[255];
   279 					char *dptr = descr;
   280 
   281 					/* Print comments until there is no more */
   282 					strncopy(descr, cvar->GetHelpText(), sizeof(descr));
   283 					while (*dptr != '\0')
   284 					{
   285 						/* Find the next line */
   286 						char *next_ptr = dptr;
   287 						while (*next_ptr != '\0')
   288 						{
   289 							if (*next_ptr == '\n')
   290 							{
   291 								*next_ptr = '\0';
   292 								next_ptr++;
   293 								break;
   294 							}
   295 							next_ptr++;
   296 						}
   297 						fprintf(fp, "// %s\n", dptr);
   298 						dptr = next_ptr;
   299 					}
   300 
   301 					fprintf(fp, "// -\n");
   302 					fprintf(fp, "// Default: \"%s\"\n", cvar->GetDefault());
   303 					if (cvar->GetMin(x))
   304 					{
   305 						fprintf(fp, "// Minimum: \"%02f\"\n", x);
   306 					}
   307 					if (cvar->GetMax(x))
   308 					{
   309 						fprintf(fp, "// Maximum: \"%02f\"\n", x);
   310 					}
   311 					fprintf(fp, "%s \"%s\"\n", cvar->GetName(), cvar->GetDefault());
   312 					fprintf(fp, "\n");
   313 				}
   314 				fprintf(fp, "\n");
   315 
   316 				file_exists = true;
   317 				can_create = false;
   318 				fclose(fp);
   319 			}
   320 		}
   321 	}
   322 
   323 	if (file_exists)
   324 	{
   325 		char cmd[255];
   326 		UTIL_Format(cmd, sizeof(cmd), "exec %s\n", local);
   327 		engine->ServerCommand(cmd);
   328 	}
   329 
   330 	return can_create;
   331 }
   332 
   333 void SM_DoSingleExecFwds(IPluginContext *ctx)
   334 {
   335 	IPluginFunction *pf;
   336 
   337 	if ((pf = ctx->GetFunctionByName("OnServerCfg")) != NULL)
   338 	{
   339 		pf->Execute(NULL);
   340 	}
   341 
   342 	if ((pf = ctx->GetFunctionByName("OnConfigsExecuted")) != NULL)
   343 	{
   344 		pf->Execute(NULL);
   345 	}
   346 }
   347 
   348 void SM_ConfigsExecuted_Plugin(unsigned int serial)
   349 {
   350 	IPluginIterator *iter = g_PluginSys.GetPluginIterator();
   351 	while (iter->MorePlugins())
   352 	{
   353 		CPlugin *plugin = (CPlugin *)(iter->GetPlugin());
   354 		if (plugin->GetSerial() == serial)
   355 		{
   356 			SM_DoSingleExecFwds(plugin->GetBaseContext());
   357 			break;
   358 		}
   359 		iter->NextPlugin();
   360 	}
   361 	iter->Release();
   362 }
   363 
   364 void SM_ExecuteForPlugin(IPluginContext *ctx)
   365 {
   366 	CPlugin *plugin = (CPlugin *)g_PluginSys.GetPluginByCtx(ctx->GetContext());
   367 
   368 	unsigned int num = plugin->GetConfigCount();
   369 	if (!num)
   370 	{
   371 		SM_DoSingleExecFwds(ctx);
   372 	}
   373 	else
   374 	{
   375 		bool can_create = true;
   376 		for (unsigned int i=0; i<num; i++)
   377 		{
   378 			can_create = SM_ExecuteConfig(plugin, plugin->GetConfig(i), can_create);
   379 		}
   380 		char cmd[255];
   381 		UTIL_Format(cmd, sizeof(cmd), "sm internal 2 %d\n", plugin->GetSerial());
   382 		engine->ServerCommand(cmd);
   383 	}
   384 }
   385 
   386 void SM_ExecuteAllConfigs()
   387 {
   388 	if (g_bConfigsExecd)
   389 	{
   390 		return;
   391 	}
   392 
   393 	engine->ServerCommand("exec sourcemod/sourcemod.cfg\n");
   394 
   395 	IPluginIterator *iter = g_PluginSys.GetPluginIterator();
   396 	while (iter->MorePlugins())
   397 	{
   398 		CPlugin *plugin = (CPlugin *)(iter->GetPlugin());
   399 		unsigned int num = plugin->GetConfigCount();
   400 		bool can_create = true;
   401 		for (unsigned int i=0; i<num; i++)
   402 		{
   403 			can_create = SM_ExecuteConfig(plugin, plugin->GetConfig(i), can_create);
   404 		}
   405 		iter->NextPlugin();
   406 	}
   407 	iter->Release();
   408 
   409 	g_pOnAutoConfigsBuffered->Execute(NULL);
   410 
   411 	engine->ServerCommand("sm internal 1\n");
   412 }
   413 
   414 void SM_ConfigsExecuted_Global()
   415 {
   416 	if (g_bConfigsExecd)
   417 	{
   418 		return;
   419 	}
   420 
   421 	g_bConfigsExecd = true;
   422 
   423 	g_pOnServerCfg->Execute(NULL);
   424 	g_pOnConfigsExecuted->Execute(NULL);
   425 }