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