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