extensions/clientprefs/cookie.cpp
author Kyle Sanderson <kyle.leet@gmail.com>
Thu Feb 28 21:51:49 2013 +0000 (2013-02-28)
changeset 3804 90159516acd3
parent 3536 fddd9e8bdef5
child 3829 2d31287c982f
permissions -rw-r--r--
Overhaul of ClientPrefs extension (bug 5538, r=asherkin).
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 "cookie.h"
pred@2048
    33
#include "menus.h"
pred@2009
    34
#include "query.h"
pred@2009
    35
pred@2009
    36
CookieManager g_CookieManager;
pred@2009
    37
pred@2009
    38
CookieManager::CookieManager()
pred@2009
    39
{
pred@2009
    40
	for (int i=0; i<=MAXCLIENTS; i++)
pred@2009
    41
	{
pred@2009
    42
		connected[i] = false;
pred@2009
    43
		statsLoaded[i] = false;
kyle@3804
    44
		statsPending[i] = false;
pred@2009
    45
	}
pred@2009
    46
pred@2048
    47
	cookieDataLoadedForward = NULL;
pred@2048
    48
	clientMenu = NULL;
pred@2009
    49
}
pred@2009
    50
CookieManager::~CookieManager(){}
pred@2009
    51
pred@2009
    52
void CookieManager::Unload()
pred@2009
    53
{
pred@2009
    54
	/* If clients are connected we should try save their data */
kyle@3804
    55
	for (int i = playerhelpers->GetMaxClients()+1; --i > 0;)
pred@2009
    56
	{
pred@2009
    57
		if (connected[i])
pred@2009
    58
		{
pred@2009
    59
			OnClientDisconnecting(i);
pred@2009
    60
		}
pred@2009
    61
	}
pred@2009
    62
pred@2009
    63
	/* Find all cookies and delete them */
pred@2009
    64
	Cookie *current;
pred@2009
    65
kyle@3804
    66
	for (SourceHook::List<Cookie *>::iterator _iter = cookieList.begin(); _iter != cookieList.end(); _iter++)
pred@2009
    67
	{
pred@2009
    68
		current = (Cookie *)*_iter;
pred@2009
    69
pred@2009
    70
		if (current == NULL)
pred@2009
    71
		{
pred@2009
    72
			continue;
pred@2009
    73
		}
pred@2009
    74
pred@2207
    75
		g_ClientPrefs.cookieMutex->Lock();
pred@2207
    76
		if (current->usedInQuery)
pred@2207
    77
		{
pred@2207
    78
			current->shouldDelete = true;
pred@2207
    79
			g_ClientPrefs.cookieMutex->Unlock();
pred@2207
    80
		}
pred@2207
    81
		else
pred@2207
    82
		{
pred@2207
    83
			g_ClientPrefs.cookieMutex->Unlock();
pred@2207
    84
			delete current;
pred@2207
    85
		}
pred@2009
    86
	}
kyle@3804
    87
	
kyle@3804
    88
	cookieList.clear();
pred@2009
    89
}
pred@2009
    90
pred@2009
    91
Cookie *CookieManager::FindCookie(const char *name)
pred@2009
    92
{
pred@2009
    93
	Cookie **pCookie = cookieTrie.retrieve(name);
pred@2009
    94
pred@2009
    95
	if (pCookie == NULL)
pred@2009
    96
	{
pred@2009
    97
		return NULL;
pred@2009
    98
	}
pred@2009
    99
pred@2009
   100
	return *pCookie;
pred@2009
   101
}
pred@2009
   102
pred@2048
   103
Cookie *CookieManager::CreateCookie(const char *name, const char *description, CookieAccess access)
pred@2009
   104
{
pred@2009
   105
	Cookie *pCookie = FindCookie(name);
pred@2009
   106
pred@2009
   107
	/* Check if cookie already exists */
pred@2009
   108
	if (pCookie != NULL)
pred@2009
   109
	{
pred@2048
   110
		/* Update data fields to the provided values */
kyle@3804
   111
		UTIL_strncpy(pCookie->description, description, MAX_DESC_LENGTH);
pred@2048
   112
		pCookie->access = access;
pred@2048
   113
pred@2009
   114
		return pCookie;
pred@2009
   115
	}
pred@2009
   116
pred@2009
   117
	/* First time cookie - Create from scratch */
pred@2048
   118
	pCookie = new Cookie(name, description, access);
kyle@3804
   119
	pCookie->usedInQuery++;
kyle@3804
   120
	
kyle@3804
   121
	/* Attempt to insert cookie into the db and get its ID num */
kyle@3804
   122
	TQueryOp *op = new TQueryOp(Query_InsertCookie, pCookie);
kyle@3804
   123
	op->m_params.cookie = pCookie;
kyle@3804
   124
	
pred@2009
   125
	cookieTrie.insert(name, pCookie);
pred@2009
   126
	cookieList.push_back(pCookie);
pred@2009
   127
pred@2207
   128
	g_ClientPrefs.AddQueryToQueue(op);
pred@2009
   129
pred@2009
   130
	return pCookie;
pred@2009
   131
}
pred@2009
   132
pred@2009
   133
bool CookieManager::GetCookieValue(Cookie *pCookie, int client, char **value)
pred@2009
   134
{
pred@2009
   135
	CookieData *data = pCookie->data[client];
pred@2009
   136
pred@2009
   137
	/* Check if a value has been set before */
pred@2009
   138
	if (data == NULL)
pred@2009
   139
	{
pred@2009
   140
		data = new CookieData("");
pred@2009
   141
		data->parent = pCookie;
pred@2009
   142
		clientData[client].push_back(data);
pred@2009
   143
		pCookie->data[client] = data;
kyle@3804
   144
		data->changed = false;
kyle@3804
   145
		data->timestamp = 0;
pred@2009
   146
	}
pred@2009
   147
pred@2009
   148
	*value = &data->value[0];
pred@2009
   149
pred@2009
   150
	return true;
pred@2009
   151
}
pred@2009
   152
fyrenmoo@2982
   153
bool CookieManager::SetCookieValue(Cookie *pCookie, int client, const char *value)
pred@2009
   154
{
pred@2009
   155
	CookieData *data = pCookie->data[client];
pred@2009
   156
pred@2009
   157
	if (data == NULL)
pred@2009
   158
	{
pred@2009
   159
		data = new CookieData(value);
pred@2009
   160
		data->parent = pCookie;
pred@2009
   161
		clientData[client].push_back(data);
pred@2009
   162
		pCookie->data[client] = data;
pred@2009
   163
	}
pred@2009
   164
	else
pred@2009
   165
	{
kyle@3804
   166
		UTIL_strncpy(data->value, value, MAX_VALUE_LENGTH);
pred@2009
   167
	}
pred@2009
   168
pred@2009
   169
	data->changed = true;
pred@2668
   170
	data->timestamp = time(NULL);
pred@2009
   171
pred@2009
   172
	return true;
pred@2009
   173
}
pred@2009
   174
pred@2009
   175
void CookieManager::OnClientAuthorized(int client, const char *authstring)
pred@2009
   176
{
dvander@2380
   177
	IGamePlayer *player = playerhelpers->GetGamePlayer(client);
dvander@2380
   178
dvander@2380
   179
	if (player == NULL)
dvander@2380
   180
	{
dvander@2380
   181
		return;
dvander@2380
   182
	}
dvander@2380
   183
pred@2009
   184
	connected[client] = true;
kyle@3804
   185
	statsPending[client] = true;
pred@2009
   186
kyle@3804
   187
	g_ClientPrefs.AttemptReconnection();
kyle@3804
   188
	
pred@2592
   189
	TQueryOp *op = new TQueryOp(Query_SelectData, player->GetSerial());
kyle@3804
   190
	UTIL_strncpy(op->m_params.steamId, authstring, MAX_NAME_LENGTH);
pred@2207
   191
pred@2207
   192
	g_ClientPrefs.AddQueryToQueue(op);
pred@2009
   193
}
pred@2009
   194
pred@2009
   195
void CookieManager::OnClientDisconnecting(int client)
pred@2009
   196
{
pred@2009
   197
	connected[client] = false;
pred@2009
   198
	statsLoaded[client] = false;
kyle@3804
   199
	statsPending[client] = false;
pred@2009
   200
pred@2009
   201
	CookieData *current;
pred@2009
   202
kyle@3804
   203
	g_ClientPrefs.AttemptReconnection();
kyle@3804
   204
	
kyle@3804
   205
	/* Save this cookie to the database */
kyle@3804
   206
	IGamePlayer *player = playerhelpers->GetGamePlayer(client);
kyle@3804
   207
	const char *pAuth = NULL;
kyle@3804
   208
	int dbId;
kyle@3804
   209
	
kyle@3804
   210
	if (player)
pred@2009
   211
	{
kyle@3804
   212
		pAuth = player->GetAuthString();
kyle@3804
   213
	}
kyle@3804
   214
	
kyle@3804
   215
	g_ClientPrefs.ClearQueryCache(player->GetSerial());
kyle@3804
   216
	
kyle@3804
   217
	for (SourceHook::List<CookieData *>::iterator _iter = clientData[client].begin();\
kyle@3804
   218
	_iter != clientData[client].end(); _iter++)
kyle@3804
   219
	{
kyle@3804
   220
		if (player == NULL || pAuth == NULL)
kyle@3804
   221
		{
kyle@3804
   222
			/* panic! */
kyle@3804
   223
			current->parent->data[client] = NULL;
kyle@3804
   224
			delete current;
kyle@3804
   225
			continue;
kyle@3804
   226
		}
kyle@3804
   227
	
pred@2009
   228
		current = (CookieData *)*_iter;
kyle@3804
   229
		dbId = current->parent->dbid;
kyle@3804
   230
		
kyle@3804
   231
		if (!current->changed || dbId == -1)
pred@2009
   232
		{
pred@2131
   233
			current->parent->data[client] = NULL;
pred@2131
   234
			delete current;
pred@2009
   235
			continue;
pred@2009
   236
		}
pred@2009
   237
pred@2207
   238
		TQueryOp *op = new TQueryOp(Query_InsertData, client);
pred@2009
   239
kyle@3804
   240
		UTIL_strncpy(op->m_params.steamId, pAuth, MAX_NAME_LENGTH);
pred@2207
   241
		op->m_params.cookieId = dbId;
pred@2207
   242
		op->m_params.data = current;
pred@2207
   243
pred@2207
   244
		g_ClientPrefs.AddQueryToQueue(op);
pred@2009
   245
pred@2009
   246
		current->parent->data[client] = NULL;
pred@2009
   247
	}
kyle@3804
   248
	
kyle@3804
   249
	clientData[client].clear();
pred@2009
   250
}
pred@2009
   251
pred@2592
   252
void CookieManager::ClientConnectCallback(int serial, IQuery *data)
pred@2009
   253
{
dvander@2380
   254
	int client;
dvander@2373
   255
dvander@2380
   256
	/* Check validity of client */
pred@2592
   257
	if ((client = playerhelpers->GetClientFromSerial(serial)) == 0)
dvander@2380
   258
	{
dvander@2380
   259
		return;
dvander@2380
   260
	}
kyle@3804
   261
	statsPending[client] = false;
kyle@3804
   262
	
kyle@3804
   263
	IResultSet *results;
dvander@2380
   264
	/* Check validity of results */
dvander@2373
   265
	if (data == NULL || (results = data->GetResultSet()) == NULL)
pred@2009
   266
	{
pred@2009
   267
		return;
pred@2009
   268
	}
pred@2009
   269
kyle@3804
   270
	CookieData *pData;
dvander@2373
   271
	IResultRow *row;
kyle@3804
   272
	unsigned int timestamp;
kyle@3804
   273
	CookieAccess access;
kyle@3804
   274
	
kyle@3804
   275
	while (results->MoreRows() && ((row = results->FetchRow()) != NULL))
pred@2009
   276
	{
kyle@3804
   277
		const char *name = "";
pred@2009
   278
		row->GetString(0, &name, NULL);
kyle@3804
   279
		
kyle@3804
   280
		const char *value = "";
pred@2009
   281
		row->GetString(1, &value, NULL);
pred@2009
   282
kyle@3804
   283
		pData = new CookieData(value);
pred@2009
   284
		pData->changed = false;
pred@2009
   285
kyle@3804
   286
		pData->timestamp = (row->GetInt(4, (int *)&timestamp) == DBVal_Data) ? timestamp : 0;
pred@2668
   287
pred@2009
   288
		Cookie *parent = FindCookie(name);
pred@2009
   289
pred@2009
   290
		if (parent == NULL)
pred@2009
   291
		{
kyle@3804
   292
			const char *desc = "";
pred@2009
   293
			row->GetString(2, &desc, NULL);
pred@2009
   294
kyle@3804
   295
			access = CookieAccess_Public;
pred@2048
   296
			row->GetInt(3, (int *)&access);
pred@2048
   297
pred@2048
   298
			parent = CreateCookie(name, desc, access);
pred@2009
   299
		}
pred@2009
   300
pred@2009
   301
		pData->parent = parent;
pred@2009
   302
		parent->data[client] = pData;
pred@2009
   303
		clientData[client].push_back(pData);
kyle@3804
   304
	}
pred@2009
   305
pred@2009
   306
	statsLoaded[client] = true;
pred@2009
   307
pred@2048
   308
	cookieDataLoadedForward->PushCell(client);
pred@2048
   309
	cookieDataLoadedForward->Execute(NULL);
pred@2009
   310
}
pred@2009
   311
pred@2009
   312
void CookieManager::InsertCookieCallback(Cookie *pCookie, int dbId)
pred@2009
   313
{
pred@2048
   314
	if (dbId > 0)
pred@2048
   315
	{
pred@2048
   316
		pCookie->dbid = dbId;
pred@2048
   317
		return;
pred@2048
   318
	}
pred@2048
   319
pred@2207
   320
	TQueryOp *op = new TQueryOp(Query_SelectId, pCookie);
pred@2207
   321
	/* Put the cookie name into the steamId field to save space - Make sure we remember that it's there */
kyle@3804
   322
	UTIL_strncpy(op->m_params.steamId, pCookie->name, MAX_NAME_LENGTH);
pred@2207
   323
	g_ClientPrefs.AddQueryToQueue(op);
pred@2048
   324
}
pred@2048
   325
pred@2048
   326
void CookieManager::SelectIdCallback(Cookie *pCookie, IQuery *data)
pred@2048
   327
{
dvander@2373
   328
	IResultSet *results;
dvander@2373
   329
	
dvander@2373
   330
	if (data == NULL || (results = data->GetResultSet()) == NULL)
pred@2048
   331
	{
pred@2048
   332
		return;
pred@2048
   333
	}
pred@2048
   334
pred@2048
   335
	IResultRow *row = results->FetchRow();
pred@2048
   336
pred@2048
   337
	if (row == NULL)
pred@2048
   338
	{
pred@2048
   339
		return;
pred@2048
   340
	}
pred@2048
   341
pred@2048
   342
	row->GetInt(0, &pCookie->dbid);
pred@2009
   343
}
pred@2009
   344
pred@2009
   345
bool CookieManager::AreClientCookiesCached(int client)
pred@2009
   346
{
pred@2009
   347
	return statsLoaded[client];
pred@2009
   348
}
pred@2009
   349
kyle@3804
   350
bool CookieManager::AreClientCookiesPening(int client)
kyle@3804
   351
{
kyle@3804
   352
	return statsPending[client];
kyle@3804
   353
}
kyle@3804
   354
pred@2048
   355
void CookieManager::OnPluginDestroyed(IPlugin *plugin)
pred@2048
   356
{
pred@2048
   357
	SourceHook::List<char *> *pList;
pred@2048
   358
pred@2048
   359
	if (plugin->GetProperty("SettingsMenuItems", (void **)&pList, true))
pred@2048
   360
	{
pred@2048
   361
		char *name;
kyle@3804
   362
		ItemDrawInfo draw;
kyle@3804
   363
		const char *info;
kyle@3804
   364
		AutoMenuData * data;
kyle@3804
   365
		unsigned itemcount;
kyle@3804
   366
		
kyle@3804
   367
		for (SourceHook::List<char *>::iterator p_iter = pList->begin(); p_iter != pList->end(); p_iter++)
pred@2048
   368
		{
pred@2048
   369
			name = (char *)*p_iter;
kyle@3804
   370
			itemcount = clientMenu->GetItemCount();
kyle@3804
   371
			//remove from this plugins list
kyle@3804
   372
			for (unsigned int i=0; i < itemcount; i++)
pred@2048
   373
			{
kyle@3804
   374
				info = clientMenu->GetItemInfo(i, &draw);
pred@2048
   375
pred@2048
   376
				if (info == NULL)
pred@2048
   377
				{
pred@2048
   378
					continue;
pred@2048
   379
				}
pred@2048
   380
pred@2048
   381
				if (strcmp(draw.display, name) == 0)
pred@2048
   382
				{
kyle@3804
   383
					data = (AutoMenuData *)strtoul(info, NULL, 16);
pred@2048
   384
pred@2048
   385
					if (data->handler->forward != NULL)
pred@2048
   386
					{
pred@2048
   387
						forwards->ReleaseForward(data->handler->forward);
pred@2048
   388
					}
pred@2048
   389
					delete data->handler;
pred@2048
   390
					delete data;
pred@2048
   391
pred@2048
   392
					clientMenu->RemoveItem(i);
pred@2048
   393
					break;
pred@2048
   394
				}
pred@2048
   395
			}
pred@2048
   396
kyle@3804
   397
			delete [] name;
kyle@3804
   398
		}
kyle@3804
   399
		
kyle@3804
   400
		pList->clear();
pred@2048
   401
	}
pred@2048
   402
}
dvander@2373
   403
pred@2668
   404
bool CookieManager::GetCookieTime(Cookie *pCookie, int client, time_t *value)
pred@2668
   405
{
pred@2668
   406
	CookieData *data = pCookie->data[client];
pred@2668
   407
pred@2668
   408
	/* Check if a value has been set before */
pred@2668
   409
	if (data == NULL)
pred@2668
   410
	{
pred@2668
   411
		return false;
pred@2668
   412
	}
pred@2668
   413
pred@2668
   414
	*value = data->timestamp;
pred@2668
   415
pred@2668
   416
	return true;
pred@2668
   417
}