extensions/clientprefs/natives.cpp
author David Anderson <dvander@alliedmods.net>
Mon Aug 10 22:16:58 2009 -0400 (2009-08-10)
changeset 2767 c1f37afdcbb9
parent 2668 a6c7e8d7f8c9
child 2915 9aeeddddd22e
permissions -rw-r--r--
Fixed incorrect escaping in clientprefs SQLite queries (bug 3904, r+a12=pred).
pred@2009
     1
/**
pred@2009
     2
 * vim: set ts=4 :
pred@2009
     3
 * =============================================================================
pred@2009
     4
 * SourceMod Client Preferences Extension
pred@2009
     5
 * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
pred@2009
     6
 * =============================================================================
pred@2009
     7
 *
pred@2009
     8
 * This program is free software; you can redistribute it and/or modify it under
pred@2009
     9
 * the terms of the GNU General Public License, version 3.0, as published by the
pred@2009
    10
 * Free Software Foundation.
pred@2009
    11
 * 
pred@2009
    12
 * This program is distributed in the hope that it will be useful, but WITHOUT
pred@2009
    13
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
pred@2009
    14
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
pred@2009
    15
 * details.
pred@2009
    16
 *
pred@2009
    17
 * You should have received a copy of the GNU General Public License along with
pred@2009
    18
 * this program.  If not, see <http://www.gnu.org/licenses/>.
pred@2009
    19
 *
pred@2009
    20
 * As a special exception, AlliedModders LLC gives you permission to link the
pred@2009
    21
 * code of this program (as well as its derivative works) to "Half-Life 2," the
pred@2009
    22
 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
pred@2009
    23
 * by the Valve Corporation.  You must obey the GNU General Public License in
pred@2009
    24
 * all respects for all other code used.  Additionally, AlliedModders LLC grants
pred@2009
    25
 * this exception to all derivative works.  AlliedModders LLC defines further
pred@2009
    26
 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
pred@2009
    27
 * or <http://www.sourcemod.net/license.php>.
pred@2009
    28
 *
pred@2009
    29
 * Version: $Id$
pred@2009
    30
 */
pred@2009
    31
pred@2009
    32
#include "extension.h"
pred@2009
    33
#include "cookie.h"
pred@2048
    34
#include "menus.h"
pred@2009
    35
pred@2009
    36
cell_t RegClientPrefCookie(IPluginContext *pContext, const cell_t *params)
pred@2009
    37
{
pred@2207
    38
	if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading)
pred@2207
    39
	{
pred@2207
    40
		return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection");
pred@2207
    41
	}
pred@2207
    42
pred@2009
    43
	char *name;
pred@2009
    44
	pContext->LocalToString(params[1], &name);
pred@2009
    45
pred@2009
    46
	if (name[0] == '\0')
pred@2009
    47
	{
pred@2009
    48
		return pContext->ThrowNativeError("Cannot create preference cookie with no name");
pred@2009
    49
	}
pred@2009
    50
pred@2009
    51
	char *desc;
pred@2009
    52
	pContext->LocalToString(params[2], &desc);
pred@2009
    53
pred@2048
    54
	Cookie *pCookie = g_CookieManager.CreateCookie(name, desc, (CookieAccess)params[3]);
pred@2009
    55
pred@2009
    56
	if (!pCookie)
pred@2009
    57
	{
pred@2009
    58
		return BAD_HANDLE;
pred@2009
    59
	}
pred@2009
    60
pred@2009
    61
	return handlesys->CreateHandle(g_CookieType, 
pred@2009
    62
		pCookie, 
pred@2009
    63
		pContext->GetIdentity(), 
pred@2009
    64
		myself->GetIdentity(), 
pred@2009
    65
		NULL);
pred@2009
    66
}
pred@2009
    67
pred@2009
    68
cell_t FindClientPrefCookie(IPluginContext *pContext, const cell_t *params)
pred@2009
    69
{
pred@2207
    70
	if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading)
pred@2207
    71
	{
pred@2207
    72
		return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection");
pred@2207
    73
	}
pred@2207
    74
pred@2009
    75
	char *name;
pred@2009
    76
	pContext->LocalToString(params[1], &name);
pred@2009
    77
pred@2009
    78
	Cookie *pCookie = g_CookieManager.FindCookie(name);
pred@2009
    79
pred@2009
    80
	if (!pCookie)
pred@2009
    81
	{
pred@2009
    82
		return BAD_HANDLE;
pred@2009
    83
	}
pred@2009
    84
pred@2009
    85
	return handlesys->CreateHandle(g_CookieType, 
pred@2009
    86
		pCookie, 
pred@2009
    87
		pContext->GetIdentity(), 
pred@2009
    88
		myself->GetIdentity(), 
pred@2009
    89
		NULL);
pred@2009
    90
}
pred@2009
    91
pred@2009
    92
cell_t SetClientPrefCookie(IPluginContext *pContext, const cell_t *params)
pred@2009
    93
{
pred@2207
    94
	if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading)
pred@2207
    95
	{
pred@2207
    96
		return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection");
pred@2207
    97
	}
pred@2207
    98
pred@2009
    99
	int client = params[1];
pred@2009
   100
pred@2009
   101
	if ((client < 1) || (client > playerhelpers->GetMaxClients()))
pred@2009
   102
	{
pred@2009
   103
		return pContext->ThrowNativeError("Client index %d is invalid", client);
pred@2009
   104
	}
pred@2009
   105
pred@2009
   106
	Handle_t hndl = static_cast<Handle_t>(params[2]);
pred@2009
   107
	HandleError err;
pred@2009
   108
	HandleSecurity sec;
pred@2009
   109
 
pred@2009
   110
	sec.pOwner = NULL;
pred@2009
   111
	sec.pIdentity = myself->GetIdentity();
pred@2009
   112
pred@2009
   113
	Cookie *pCookie;
pred@2009
   114
pred@2009
   115
	if ((err = handlesys->ReadHandle(hndl, g_CookieType, &sec, (void **)&pCookie))
pred@2009
   116
	     != HandleError_None)
pred@2009
   117
	{
pred@2009
   118
		return pContext->ThrowNativeError("Invalid Cookie handle %x (error %d)", hndl, err);
pred@2009
   119
	}
pred@2009
   120
pred@2009
   121
	char *value;
pred@2009
   122
	pContext->LocalToString(params[3], &value);
pred@2009
   123
pred@2009
   124
	return g_CookieManager.SetCookieValue(pCookie, client, value);
pred@2009
   125
}
pred@2009
   126
pred@2009
   127
cell_t GetClientPrefCookie(IPluginContext *pContext, const cell_t *params)
pred@2009
   128
{
pred@2207
   129
	if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading)
pred@2207
   130
	{
pred@2207
   131
		return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection");
pred@2207
   132
	}
pred@2207
   133
pred@2009
   134
	int client = params[1];
pred@2009
   135
pred@2009
   136
	if ((client < 1) || (client > playerhelpers->GetMaxClients()))
pred@2009
   137
	{
pred@2009
   138
		return pContext->ThrowNativeError("Client index %d is invalid", client);
pred@2009
   139
	}
pred@2009
   140
pred@2009
   141
	Handle_t hndl = static_cast<Handle_t>(params[2]);
pred@2009
   142
	HandleError err;
pred@2009
   143
	HandleSecurity sec;
pred@2009
   144
 
pred@2009
   145
	sec.pOwner = NULL;
pred@2009
   146
	sec.pIdentity = myself->GetIdentity();
pred@2009
   147
pred@2009
   148
	Cookie *pCookie;
pred@2009
   149
pred@2009
   150
	if ((err = handlesys->ReadHandle(hndl, g_CookieType, &sec, (void **)&pCookie))
pred@2009
   151
	     != HandleError_None)
pred@2009
   152
	{
pred@2009
   153
		return pContext->ThrowNativeError("Invalid Cookie handle %x (error %d)", hndl, err);
pred@2009
   154
	}
pred@2009
   155
	
pred@2009
   156
	char *value = NULL;
pred@2009
   157
pred@2009
   158
	g_CookieManager.GetCookieValue(pCookie, client, &value);
pred@2009
   159
pred@2009
   160
	pContext->StringToLocal(params[3], params[4], value);
pred@2009
   161
pred@2009
   162
	return 1;
pred@2009
   163
}
pred@2009
   164
pred@2009
   165
cell_t AreClientCookiesCached(IPluginContext *pContext, const cell_t *params)
pred@2009
   166
{
pred@2207
   167
	if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading)
pred@2207
   168
	{
pred@2207
   169
		return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection");
pred@2207
   170
	}
pred@2207
   171
pred@2009
   172
	int client = params[1];
pred@2009
   173
pred@2009
   174
	if ((client < 1) || (client > playerhelpers->GetMaxClients()))
pred@2009
   175
	{
pred@2009
   176
		return pContext->ThrowNativeError("Client index %d is invalid", client);
pred@2009
   177
	}
pred@2009
   178
pred@2009
   179
	return g_CookieManager.AreClientCookiesCached(client);
pred@2009
   180
}
pred@2009
   181
pred@2048
   182
cell_t GetCookieAccess(IPluginContext *pContext, const cell_t *params)
pred@2048
   183
{
pred@2207
   184
	if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading)
pred@2207
   185
	{
pred@2207
   186
		return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection");
pred@2207
   187
	}
pred@2207
   188
pred@2048
   189
	Handle_t hndl = static_cast<Handle_t>(params[1]);
pred@2048
   190
	HandleError err;
pred@2048
   191
	HandleSecurity sec;
pred@2048
   192
 
pred@2048
   193
	sec.pOwner = NULL;
pred@2048
   194
	sec.pIdentity = myself->GetIdentity();
pred@2048
   195
pred@2048
   196
	Cookie *pCookie;
pred@2048
   197
pred@2048
   198
	if ((err = handlesys->ReadHandle(hndl, g_CookieType, &sec, (void **)&pCookie))
pred@2048
   199
	     != HandleError_None)
pred@2048
   200
	{
pred@2048
   201
		return pContext->ThrowNativeError("Invalid Cookie handle %x (error %d)", hndl, err);
pred@2048
   202
	}
pred@2048
   203
pred@2048
   204
	return pCookie->access;
pred@2048
   205
}
pred@2048
   206
pred@2048
   207
static cell_t GetCookieIterator(IPluginContext *pContext, const cell_t *params)
pred@2048
   208
{
pred@2207
   209
	if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading)
pred@2207
   210
	{
pred@2207
   211
		return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection");
pred@2207
   212
	}
pred@2207
   213
pred@2048
   214
	SourceHook::List<Cookie *>::iterator *iter = new SourceHook::List<Cookie *>::iterator;
pred@2048
   215
	*iter = g_CookieManager.cookieList.begin();
pred@2048
   216
pred@2048
   217
	Handle_t hndl = handlesys->CreateHandle(g_CookieIterator, iter, pContext->GetIdentity(), myself->GetIdentity(), NULL);
pred@2048
   218
	if (hndl == BAD_HANDLE)
pred@2048
   219
	{
pred@2048
   220
		delete iter;
pred@2048
   221
	}
pred@2048
   222
pred@2048
   223
	return hndl;
pred@2048
   224
}
pred@2048
   225
pred@2048
   226
static cell_t ReadCookieIterator(IPluginContext *pContext, const cell_t *params)
pred@2048
   227
{
pred@2207
   228
	if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading)
pred@2207
   229
	{
pred@2207
   230
		return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection");
pred@2207
   231
	}
pred@2207
   232
pred@2048
   233
	SourceHook::List<Cookie *>::iterator *iter;
pred@2048
   234
pred@2048
   235
	Handle_t hndl = static_cast<Handle_t>(params[1]);
pred@2048
   236
	HandleError err;
pred@2048
   237
	HandleSecurity sec;
pred@2048
   238
pred@2048
   239
	sec.pOwner = NULL;
pred@2048
   240
	sec.pIdentity = myself->GetIdentity();
pred@2048
   241
pred@2048
   242
	if ((err = handlesys->ReadHandle(hndl, g_CookieIterator, &sec, (void **)&iter))
pred@2048
   243
	     != HandleError_None)
pred@2048
   244
	{
pred@2048
   245
		return pContext->ThrowNativeError("Invalid Cookie iterator handle %x (error %d)", hndl, err);
pred@2048
   246
	}
pred@2048
   247
pred@2048
   248
	if (*iter == g_CookieManager.cookieList.end())
pred@2048
   249
	{
pred@2048
   250
		return 0;
pred@2048
   251
	}
pred@2048
   252
pred@2048
   253
	Cookie *pCookie = (Cookie *)**iter;
pred@2048
   254
pred@2048
   255
	(*iter)++;
pred@2048
   256
pred@2048
   257
	pContext->StringToLocalUTF8(params[2], params[3], pCookie->name, NULL);
pred@2048
   258
	pContext->StringToLocalUTF8(params[5], params[6], pCookie->description, NULL);
pred@2048
   259
pred@2048
   260
	cell_t *addr;
pred@2048
   261
	pContext->LocalToPhysAddr(params[4], &addr);
pred@2048
   262
	*addr = pCookie->access;
pred@2048
   263
pred@2048
   264
	return 1;
pred@2048
   265
}
pred@2048
   266
pred@2048
   267
cell_t ShowSettingsMenu(IPluginContext *pContext, const cell_t *params)
pred@2048
   268
{
pred@2207
   269
	if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading)
pred@2207
   270
	{
pred@2207
   271
		return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection");
pred@2207
   272
	}
pred@2207
   273
pred@2048
   274
	char message[256];
pred@2048
   275
	Translate(message, sizeof(message), "%T:", 2, NULL, "Client Settings", &params[1]);
pred@2048
   276
pred@2048
   277
	g_CookieManager.clientMenu->SetDefaultTitle(message);
pred@2048
   278
	g_CookieManager.clientMenu->Display(params[1], 0, NULL);
pred@2048
   279
pred@2048
   280
	return 0;
pred@2048
   281
}
pred@2048
   282
pred@2048
   283
cell_t AddSettingsMenuItem(IPluginContext *pContext, const cell_t *params)
pred@2048
   284
{
pred@2207
   285
	if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading)
pred@2207
   286
	{
pred@2207
   287
		return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection");
pred@2207
   288
	}
pred@2207
   289
pred@2048
   290
	char *display;
pred@2048
   291
	pContext->LocalToString(params[3], &display);
pred@2048
   292
pred@2048
   293
	/* Register a callback */
pred@2048
   294
	ItemHandler *pItem = new ItemHandler;
pred@2048
   295
	pItem->isAutoMenu = false;
pred@2048
   296
	pItem->forward = forwards->CreateForwardEx(NULL, ET_Ignore, 5, NULL, Param_Cell, Param_Cell, Param_Cell, Param_String, Param_Cell);
pred@2048
   297
pred@2048
   298
	pItem->forward->AddFunction(pContext, static_cast<funcid_t>(params[1]));
pred@2048
   299
pred@2048
   300
	char info[20];
pred@2048
   301
	AutoMenuData *data = new AutoMenuData;
pred@2048
   302
	data->datavalue = params[2];
pred@2048
   303
	data->handler = pItem;
pred@2048
   304
	UTIL_Format(info, sizeof(info), "%x", data);
pred@2048
   305
pred@2048
   306
	ItemDrawInfo draw(display, 0);
pred@2048
   307
pred@2048
   308
	g_CookieManager.clientMenu->AppendItem(info, draw);
pred@2048
   309
pred@2048
   310
	/* Track this in case the plugin unloads */
pred@2048
   311
pred@2048
   312
	IPlugin *pPlugin = plsys->FindPluginByContext(pContext->GetContext());
pred@2048
   313
	SourceHook::List<char *> *pList = NULL;
pred@2048
   314
pred@2048
   315
	if (!pPlugin->GetProperty("SettingsMenuItems", (void **)&pList, false) || !pList)
pred@2048
   316
	{
pred@2048
   317
		pList = new SourceHook::List<char *>;
pred@2048
   318
		pPlugin->SetProperty("SettingsMenuItems", pList);
pred@2048
   319
	}
pred@2048
   320
pred@2048
   321
	char *copyarray = new char[strlen(display)+1];
pred@2048
   322
	UTIL_Format(copyarray, strlen(display)+1, "%s", display);
pred@2048
   323
pred@2048
   324
	pList->push_back(copyarray);
pred@2048
   325
pred@2048
   326
	return 0;
pred@2048
   327
}
pred@2048
   328
pred@2048
   329
cell_t AddSettingsPrefabMenuItem(IPluginContext *pContext, const cell_t *params)
pred@2048
   330
{
pred@2207
   331
	if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading)
pred@2207
   332
	{
pred@2207
   333
		return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection");
pred@2207
   334
	}
pred@2207
   335
pred@2048
   336
	Handle_t hndl = static_cast<Handle_t>(params[1]);
pred@2048
   337
	HandleError err;
pred@2048
   338
	HandleSecurity sec;
pred@2048
   339
 
pred@2048
   340
	sec.pOwner = NULL;
pred@2048
   341
	sec.pIdentity = myself->GetIdentity();
pred@2048
   342
pred@2048
   343
	Cookie *pCookie;
pred@2048
   344
pred@2048
   345
	if ((err = handlesys->ReadHandle(hndl, g_CookieType, &sec, (void **)&pCookie))
pred@2048
   346
	     != HandleError_None)
pred@2048
   347
	{
pred@2048
   348
		return pContext->ThrowNativeError("Invalid Cookie handle %x (error %d)", hndl, err);
pred@2048
   349
	}
pred@2048
   350
pred@2048
   351
	/* Register a callback */
pred@2048
   352
	ItemHandler *pItem = new ItemHandler;
pred@2048
   353
	pItem->isAutoMenu = true;
pred@2048
   354
	pItem->autoMenuType = (CookieMenu)params[2];
pred@2048
   355
pred@2048
   356
pred@2048
   357
	/* User passed a function id for a callback */
pred@2048
   358
	if (params[4] != -1)
pred@2048
   359
	{
pred@2048
   360
		pItem->forward = forwards->CreateForwardEx(NULL, ET_Ignore, 5, NULL, Param_Cell, Param_Cell, Param_Cell, Param_String, Param_Cell); 
pred@2048
   361
		pItem->forward->AddFunction(pContext, static_cast<funcid_t>(params[4]));
pred@2048
   362
	}
pred@2048
   363
	else
pred@2048
   364
	{
pred@2048
   365
		pItem->forward = NULL;
pred@2048
   366
	}
pred@2048
   367
pred@2048
   368
	char *display;
pred@2048
   369
	pContext->LocalToString(params[3], &display);
pred@2048
   370
pred@2048
   371
	ItemDrawInfo draw(display, 0);
pred@2048
   372
pred@2048
   373
	char info[20];
pred@2048
   374
	AutoMenuData *data = new AutoMenuData;
pred@2048
   375
	data->datavalue = params[5];
pred@2048
   376
	data->pCookie = pCookie;
pred@2048
   377
	data->type = (CookieMenu)params[2];
pred@2048
   378
	data->handler = pItem;
pred@2048
   379
	UTIL_Format(info, sizeof(info), "%x", data);
pred@2048
   380
pred@2048
   381
	g_CookieManager.clientMenu->AppendItem(info, draw);
pred@2048
   382
pred@2048
   383
	/* Track this in case the plugin unloads */
pred@2048
   384
pred@2048
   385
	IPlugin *pPlugin = plsys->FindPluginByContext(pContext->GetContext());
pred@2048
   386
	SourceHook::List<char *> *pList = NULL;
pred@2048
   387
pred@2048
   388
	if (!pPlugin->GetProperty("SettingsMenuItems", (void **)&pList, false) || !pList)
pred@2048
   389
	{
pred@2048
   390
		pList = new SourceHook::List<char *>;
pred@2048
   391
		pPlugin->SetProperty("SettingsMenuItems", pList);
pred@2048
   392
	}
pred@2048
   393
pred@2048
   394
	char *copyarray = new char[strlen(display)+1];
pred@2048
   395
	UTIL_Format(copyarray, strlen(display)+1, "%s", display);
pred@2048
   396
pred@2048
   397
	pList->push_back(copyarray);
pred@2048
   398
pred@2048
   399
	return 0;
pred@2048
   400
}
pred@2048
   401
pred@2668
   402
cell_t GetClientCookieTime(IPluginContext *pContext, const cell_t *params)
pred@2668
   403
{
pred@2668
   404
	if (g_ClientPrefs.Database == NULL && !g_ClientPrefs.databaseLoading)
pred@2668
   405
	{
pred@2668
   406
		return pContext->ThrowNativeError("Clientprefs is disabled due to a failed database connection");
pred@2668
   407
	}
pred@2668
   408
pred@2668
   409
	Handle_t hndl = static_cast<Handle_t>(params[2]);
pred@2668
   410
	HandleError err;
pred@2668
   411
	HandleSecurity sec;
pred@2668
   412
pred@2668
   413
	sec.pOwner = NULL;
pred@2668
   414
	sec.pIdentity = myself->GetIdentity();
pred@2668
   415
pred@2668
   416
	Cookie *pCookie;
pred@2668
   417
pred@2668
   418
	if ((err = handlesys->ReadHandle(hndl, g_CookieType, &sec, (void **)&pCookie))
pred@2668
   419
		!= HandleError_None)
pred@2668
   420
	{
pred@2668
   421
		return pContext->ThrowNativeError("Invalid Cookie handle %x (error %d)", hndl, err);
pred@2668
   422
	}
pred@2668
   423
pred@2668
   424
	time_t value;
pred@2668
   425
pred@2668
   426
	if (!g_CookieManager.GetCookieTime(pCookie, params[1], &value))
pred@2668
   427
	{
pred@2668
   428
		return 0;
pred@2668
   429
	}
pred@2668
   430
pred@2668
   431
	return value;
pred@2668
   432
}
pred@2668
   433
pred@2009
   434
sp_nativeinfo_t g_ClientPrefNatives[] = 
pred@2009
   435
{
pred@2048
   436
	{"RegClientCookie",				RegClientPrefCookie},
pred@2048
   437
	{"FindClientCookie",			FindClientPrefCookie},
pred@2048
   438
	{"SetClientCookie",				SetClientPrefCookie},
pred@2048
   439
	{"GetClientCookie",				GetClientPrefCookie},
pred@2009
   440
	{"AreClientCookiesCached",		AreClientCookiesCached},
pred@2048
   441
	{"GetCookieAccess",				GetCookieAccess},
pred@2048
   442
	{"ReadCookieIterator",			ReadCookieIterator},
pred@2048
   443
	{"GetCookieIterator",			GetCookieIterator},
pred@2048
   444
	{"ShowCookieMenu",				ShowSettingsMenu},
pred@2048
   445
	{"SetCookieMenuItem",			AddSettingsMenuItem},
pred@2048
   446
	{"SetCookiePrefabMenu",			AddSettingsPrefabMenuItem},
pred@2009
   447
	{NULL,							NULL}
pred@2009
   448
};