extensions/clientprefs/natives.cpp
author Don <datal30mb@users.sourceforge.net>
Fri Oct 14 11:28:53 2011 -0400 (2011-10-14)
changeset 3411 0a2e40a50757
parent 2915 9aeeddddd22e
child 3804 90159516acd3
permissions -rw-r--r--
Added native to clientprefs to alter data on a disconnected player (bug 3882, r=pred).
     1 /**
     2  * vim: set ts=4 :
     3  * =============================================================================
     4  * SourceMod Client Preferences Extension
     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 "extension.h"
    33 #include "cookie.h"
    34 #include "menus.h"
    35 
    36 cell_t RegClientPrefCookie(IPluginContext *pContext, const cell_t *params)
    37 {
    38 	if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading)
    39 	{
    40 		return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection");
    41 	}
    42 
    43 	char *name;
    44 	pContext->LocalToString(params[1], &name);
    45 
    46 	if (name[0] == '\0')
    47 	{
    48 		return pContext->ThrowNativeError("Cannot create preference cookie with no name");
    49 	}
    50 
    51 	char *desc;
    52 	pContext->LocalToString(params[2], &desc);
    53 
    54 	Cookie *pCookie = g_CookieManager.CreateCookie(name, desc, (CookieAccess)params[3]);
    55 
    56 	if (!pCookie)
    57 	{
    58 		return BAD_HANDLE;
    59 	}
    60 
    61 	return handlesys->CreateHandle(g_CookieType, 
    62 		pCookie, 
    63 		pContext->GetIdentity(), 
    64 		myself->GetIdentity(), 
    65 		NULL);
    66 }
    67 
    68 cell_t FindClientPrefCookie(IPluginContext *pContext, const cell_t *params)
    69 {
    70 	if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading)
    71 	{
    72 		return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection");
    73 	}
    74 
    75 	char *name;
    76 	pContext->LocalToString(params[1], &name);
    77 
    78 	Cookie *pCookie = g_CookieManager.FindCookie(name);
    79 
    80 	if (!pCookie)
    81 	{
    82 		return BAD_HANDLE;
    83 	}
    84 
    85 	return handlesys->CreateHandle(g_CookieType, 
    86 		pCookie, 
    87 		pContext->GetIdentity(), 
    88 		myself->GetIdentity(), 
    89 		NULL);
    90 }
    91 
    92 cell_t SetAuthIdCookie(IPluginContext *pContext, const cell_t *params)
    93 {
    94 	if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading)
    95 	{
    96 		return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection");
    97 	}
    98 
    99 	char *steamID;
   100 	pContext->LocalToString(params[1], &steamID);
   101 
   102 	// convert cookie handle to Cookie*
   103 	Handle_t hndl = static_cast<Handle_t>(params[2]);
   104 	HandleError err;
   105 	HandleSecurity sec;
   106  
   107 	sec.pOwner = NULL;
   108 	sec.pIdentity = myself->GetIdentity();
   109 
   110 	Cookie *pCookie;
   111 
   112 	if ((err = handlesys->ReadHandle(hndl, g_CookieType, &sec, (void **)&pCookie))
   113 	     != HandleError_None)
   114 	{
   115 		return pContext->ThrowNativeError("Invalid Cookie handle %x (error %d)", hndl, err);
   116 	}
   117 
   118 	int i_dbId = pCookie->dbid;
   119 	char *value;
   120 	pContext->LocalToString(params[3], &value);
   121 
   122 	// make sure the steamID isn't currently connected
   123 	if (int client = IsAuthIdConnected(steamID))
   124 	{
   125 		// use regular code for connected players
   126 		return g_CookieManager.SetCookieValue(pCookie, client, value);
   127 	}
   128 
   129 	// constructor calls strncpy for us
   130 	CookieData *payload = new CookieData(value);
   131 
   132 	// set changed so players connecting later in during the same map will have the correct value
   133 	payload->changed = true;
   134 	payload->timestamp = time(NULL);
   135 
   136 	// edit database table
   137 	TQueryOp *op = new TQueryOp(Query_InsertData, pCookie);
   138 	// limit player auth length which doubles for cookie name length
   139 	strncpy(op->m_params.steamId, steamID, MAX_NAME_LENGTH);
   140 	op->m_params.steamId[MAX_NAME_LENGTH-1] = '\0';
   141 	op->m_params.cookieId = i_dbId;
   142 	op->m_params.data = payload;
   143 
   144 	g_ClientPrefs.AddQueryToQueue(op);
   145 
   146 	return 1;
   147 }
   148 
   149 cell_t SetClientPrefCookie(IPluginContext *pContext, const cell_t *params)
   150 {
   151 	if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading)
   152 	{
   153 		return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection");
   154 	}
   155 
   156 	int client = params[1];
   157 
   158 	if ((client < 1) || (client > playerhelpers->GetMaxClients()))
   159 	{
   160 		return pContext->ThrowNativeError("Client index %d is invalid", client);
   161 	}
   162 
   163 	Handle_t hndl = static_cast<Handle_t>(params[2]);
   164 	HandleError err;
   165 	HandleSecurity sec;
   166  
   167 	sec.pOwner = NULL;
   168 	sec.pIdentity = myself->GetIdentity();
   169 
   170 	Cookie *pCookie;
   171 
   172 	if ((err = handlesys->ReadHandle(hndl, g_CookieType, &sec, (void **)&pCookie))
   173 	     != HandleError_None)
   174 	{
   175 		return pContext->ThrowNativeError("Invalid Cookie handle %x (error %d)", hndl, err);
   176 	}
   177 
   178 	char *value;
   179 	pContext->LocalToString(params[3], &value);
   180 
   181 	return g_CookieManager.SetCookieValue(pCookie, client, value);
   182 }
   183 
   184 cell_t GetClientPrefCookie(IPluginContext *pContext, const cell_t *params)
   185 {
   186 	if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading)
   187 	{
   188 		return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection");
   189 	}
   190 
   191 	int client = params[1];
   192 
   193 	if ((client < 1) || (client > playerhelpers->GetMaxClients()))
   194 	{
   195 		return pContext->ThrowNativeError("Client index %d is invalid", client);
   196 	}
   197 
   198 	Handle_t hndl = static_cast<Handle_t>(params[2]);
   199 	HandleError err;
   200 	HandleSecurity sec;
   201  
   202 	sec.pOwner = NULL;
   203 	sec.pIdentity = myself->GetIdentity();
   204 
   205 	Cookie *pCookie;
   206 
   207 	if ((err = handlesys->ReadHandle(hndl, g_CookieType, &sec, (void **)&pCookie))
   208 	     != HandleError_None)
   209 	{
   210 		return pContext->ThrowNativeError("Invalid Cookie handle %x (error %d)", hndl, err);
   211 	}
   212 	
   213 	char *value = NULL;
   214 
   215 	g_CookieManager.GetCookieValue(pCookie, client, &value);
   216 
   217 	pContext->StringToLocal(params[3], params[4], value);
   218 
   219 	return 1;
   220 }
   221 
   222 cell_t AreClientCookiesCached(IPluginContext *pContext, const cell_t *params)
   223 {
   224 	if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading)
   225 	{
   226 		return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection");
   227 	}
   228 
   229 	int client = params[1];
   230 
   231 	if ((client < 1) || (client > playerhelpers->GetMaxClients()))
   232 	{
   233 		return pContext->ThrowNativeError("Client index %d is invalid", client);
   234 	}
   235 
   236 	return g_CookieManager.AreClientCookiesCached(client);
   237 }
   238 
   239 cell_t GetCookieAccess(IPluginContext *pContext, const cell_t *params)
   240 {
   241 	if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading)
   242 	{
   243 		return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection");
   244 	}
   245 
   246 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   247 	HandleError err;
   248 	HandleSecurity sec;
   249  
   250 	sec.pOwner = NULL;
   251 	sec.pIdentity = myself->GetIdentity();
   252 
   253 	Cookie *pCookie;
   254 
   255 	if ((err = handlesys->ReadHandle(hndl, g_CookieType, &sec, (void **)&pCookie))
   256 	     != HandleError_None)
   257 	{
   258 		return pContext->ThrowNativeError("Invalid Cookie handle %x (error %d)", hndl, err);
   259 	}
   260 
   261 	return pCookie->access;
   262 }
   263 
   264 static cell_t GetCookieIterator(IPluginContext *pContext, const cell_t *params)
   265 {
   266 	if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading)
   267 	{
   268 		return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection");
   269 	}
   270 
   271 	SourceHook::List<Cookie *>::iterator *iter = new SourceHook::List<Cookie *>::iterator;
   272 	*iter = g_CookieManager.cookieList.begin();
   273 
   274 	Handle_t hndl = handlesys->CreateHandle(g_CookieIterator, iter, pContext->GetIdentity(), myself->GetIdentity(), NULL);
   275 	if (hndl == BAD_HANDLE)
   276 	{
   277 		delete iter;
   278 	}
   279 
   280 	return hndl;
   281 }
   282 
   283 static cell_t ReadCookieIterator(IPluginContext *pContext, const cell_t *params)
   284 {
   285 	if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading)
   286 	{
   287 		return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection");
   288 	}
   289 
   290 	SourceHook::List<Cookie *>::iterator *iter;
   291 
   292 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   293 	HandleError err;
   294 	HandleSecurity sec;
   295 
   296 	sec.pOwner = NULL;
   297 	sec.pIdentity = myself->GetIdentity();
   298 
   299 	if ((err = handlesys->ReadHandle(hndl, g_CookieIterator, &sec, (void **)&iter))
   300 	     != HandleError_None)
   301 	{
   302 		return pContext->ThrowNativeError("Invalid Cookie iterator handle %x (error %d)", hndl, err);
   303 	}
   304 
   305 	if (*iter == g_CookieManager.cookieList.end())
   306 	{
   307 		return 0;
   308 	}
   309 
   310 	Cookie *pCookie = (Cookie *)**iter;
   311 
   312 	(*iter)++;
   313 
   314 	pContext->StringToLocalUTF8(params[2], params[3], pCookie->name, NULL);
   315 	pContext->StringToLocalUTF8(params[5], params[6], pCookie->description, NULL);
   316 
   317 	cell_t *addr;
   318 	pContext->LocalToPhysAddr(params[4], &addr);
   319 	*addr = pCookie->access;
   320 
   321 	return 1;
   322 }
   323 
   324 cell_t ShowSettingsMenu(IPluginContext *pContext, const cell_t *params)
   325 {
   326 	if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading)
   327 	{
   328 		return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection");
   329 	}
   330 
   331 	char message[256];
   332 	Translate(message, sizeof(message), "%T:", 2, NULL, "Client Settings", &params[1]);
   333 
   334 	g_CookieManager.clientMenu->SetDefaultTitle(message);
   335 	g_CookieManager.clientMenu->Display(params[1], 0, NULL);
   336 
   337 	return 0;
   338 }
   339 
   340 cell_t AddSettingsMenuItem(IPluginContext *pContext, const cell_t *params)
   341 {
   342 	if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading)
   343 	{
   344 		return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection");
   345 	}
   346 
   347 	char *display;
   348 	pContext->LocalToString(params[3], &display);
   349 
   350 	/* Register a callback */
   351 	ItemHandler *pItem = new ItemHandler;
   352 	pItem->isAutoMenu = false;
   353 	pItem->forward = forwards->CreateForwardEx(NULL, ET_Ignore, 5, NULL, Param_Cell, Param_Cell, Param_Cell, Param_String, Param_Cell);
   354 
   355 	pItem->forward->AddFunction(pContext, static_cast<funcid_t>(params[1]));
   356 
   357 	char info[20];
   358 	AutoMenuData *data = new AutoMenuData;
   359 	data->datavalue = params[2];
   360 	data->handler = pItem;
   361 	UTIL_Format(info, sizeof(info), "%x", data);
   362 
   363 	ItemDrawInfo draw(display, 0);
   364 
   365 	g_CookieManager.clientMenu->AppendItem(info, draw);
   366 
   367 	/* Track this in case the plugin unloads */
   368 
   369 	IPlugin *pPlugin = plsys->FindPluginByContext(pContext->GetContext());
   370 	SourceHook::List<char *> *pList = NULL;
   371 
   372 	if (!pPlugin->GetProperty("SettingsMenuItems", (void **)&pList, false) || !pList)
   373 	{
   374 		pList = new SourceHook::List<char *>;
   375 		pPlugin->SetProperty("SettingsMenuItems", pList);
   376 	}
   377 
   378 	char *copyarray = new char[strlen(display)+1];
   379 	UTIL_Format(copyarray, strlen(display)+1, "%s", display);
   380 
   381 	pList->push_back(copyarray);
   382 
   383 	return 0;
   384 }
   385 
   386 cell_t AddSettingsPrefabMenuItem(IPluginContext *pContext, const cell_t *params)
   387 {
   388 	if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading)
   389 	{
   390 		return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection");
   391 	}
   392 
   393 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   394 	HandleError err;
   395 	HandleSecurity sec;
   396  
   397 	sec.pOwner = NULL;
   398 	sec.pIdentity = myself->GetIdentity();
   399 
   400 	Cookie *pCookie;
   401 
   402 	if ((err = handlesys->ReadHandle(hndl, g_CookieType, &sec, (void **)&pCookie))
   403 	     != HandleError_None)
   404 	{
   405 		return pContext->ThrowNativeError("Invalid Cookie handle %x (error %d)", hndl, err);
   406 	}
   407 
   408 	/* Register a callback */
   409 	ItemHandler *pItem = new ItemHandler;
   410 	pItem->isAutoMenu = true;
   411 	pItem->autoMenuType = (CookieMenu)params[2];
   412 
   413 
   414 	/* User passed a function id for a callback */
   415 	if (params[4] != -1)
   416 	{
   417 		pItem->forward = forwards->CreateForwardEx(NULL, ET_Ignore, 5, NULL, Param_Cell, Param_Cell, Param_Cell, Param_String, Param_Cell); 
   418 		pItem->forward->AddFunction(pContext, static_cast<funcid_t>(params[4]));
   419 	}
   420 	else
   421 	{
   422 		pItem->forward = NULL;
   423 	}
   424 
   425 	char *display;
   426 	pContext->LocalToString(params[3], &display);
   427 
   428 	ItemDrawInfo draw(display, 0);
   429 
   430 	char info[20];
   431 	AutoMenuData *data = new AutoMenuData;
   432 	data->datavalue = params[5];
   433 	data->pCookie = pCookie;
   434 	data->type = (CookieMenu)params[2];
   435 	data->handler = pItem;
   436 	UTIL_Format(info, sizeof(info), "%x", data);
   437 
   438 	g_CookieManager.clientMenu->AppendItem(info, draw);
   439 
   440 	/* Track this in case the plugin unloads */
   441 
   442 	IPlugin *pPlugin = plsys->FindPluginByContext(pContext->GetContext());
   443 	SourceHook::List<char *> *pList = NULL;
   444 
   445 	if (!pPlugin->GetProperty("SettingsMenuItems", (void **)&pList, false) || !pList)
   446 	{
   447 		pList = new SourceHook::List<char *>;
   448 		pPlugin->SetProperty("SettingsMenuItems", pList);
   449 	}
   450 
   451 	char *copyarray = new char[strlen(display)+1];
   452 	UTIL_Format(copyarray, strlen(display)+1, "%s", display);
   453 
   454 	pList->push_back(copyarray);
   455 
   456 	return 0;
   457 }
   458 
   459 cell_t GetClientCookieTime(IPluginContext *pContext, const cell_t *params)
   460 {
   461 	if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading)
   462 	{
   463 		return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection");
   464 	}
   465 
   466 	Handle_t hndl = static_cast<Handle_t>(params[2]);
   467 	HandleError err;
   468 	HandleSecurity sec;
   469 
   470 	sec.pOwner = NULL;
   471 	sec.pIdentity = myself->GetIdentity();
   472 
   473 	Cookie *pCookie;
   474 
   475 	if ((err = handlesys->ReadHandle(hndl, g_CookieType, &sec, (void **)&pCookie))
   476 		!= HandleError_None)
   477 	{
   478 		return pContext->ThrowNativeError("Invalid Cookie handle %x (error %d)", hndl, err);
   479 	}
   480 
   481 	time_t value;
   482 
   483 	if (!g_CookieManager.GetCookieTime(pCookie, params[1], &value))
   484 	{
   485 		return 0;
   486 	}
   487 
   488 	return value;
   489 }
   490 
   491 sp_nativeinfo_t g_ClientPrefNatives[] = 
   492 {
   493 	{"RegClientCookie",				RegClientPrefCookie},
   494 	{"FindClientCookie",			FindClientPrefCookie},
   495 	{"SetClientCookie",				SetClientPrefCookie},
   496 	{"SetAuthIdCookie",				SetAuthIdCookie},
   497 	{"GetClientCookie",				GetClientPrefCookie},
   498 	{"AreClientCookiesCached",		AreClientCookiesCached},
   499 	{"GetCookieAccess",				GetCookieAccess},
   500 	{"ReadCookieIterator",			ReadCookieIterator},
   501 	{"GetCookieIterator",			GetCookieIterator},
   502 	{"ShowCookieMenu",				ShowSettingsMenu},
   503 	{"SetCookieMenuItem",			AddSettingsMenuItem},
   504 	{"SetCookiePrefabMenu",			AddSettingsPrefabMenuItem},
   505 	{"GetClientCookieTime",         GetClientCookieTime},
   506 	{NULL,							NULL}
   507 };