extensions/clientprefs/extension.cpp
author Nicholas Hastings <skamonkey@gmail.com>
Thu Jul 04 11:28:32 2013 -0400 (2013-07-04)
changeset 3931 576fa42454dc
parent 3804 90159516acd3
child 4029 cf8bdfcf6503
permissions -rw-r--r--
Fixed build for real.
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
dvander@2783
    32
#include <sourcemod_version.h>
pred@2009
    33
#include "extension.h"
pred@2009
    34
pred@2009
    35
/**
pred@2009
    36
 * @file extension.cpp
pred@2009
    37
 * @brief Implement extension code here.
pred@2009
    38
 */
pred@2009
    39
pred@2009
    40
ClientPrefs g_ClientPrefs;		/**< Global singleton for extension's main interface */
pred@2009
    41
pred@2009
    42
SMEXT_LINK(&g_ClientPrefs);
pred@2009
    43
pred@2009
    44
HandleType_t g_CookieType = 0;
pred@2009
    45
CookieTypeHandler g_CookieTypeHandler;
pred@2009
    46
pred@2048
    47
HandleType_t g_CookieIterator = 0;
pred@2048
    48
CookieIteratorHandler g_CookieIteratorHandler;
dvander@2373
    49
DbDriver g_DriverType;
pred@2009
    50
pred@2009
    51
bool ClientPrefs::SDK_OnLoad(char *error, size_t maxlength, bool late)
pred@2207
    52
{
pred@2207
    53
	queryMutex = threader->MakeMutex();
pred@2207
    54
	cookieMutex = threader->MakeMutex();
pred@2207
    55
pred@2207
    56
	DBInfo = dbi->FindDatabaseConf("clientprefs");
pred@2009
    57
pred@2009
    58
	if (DBInfo == NULL)
pred@2009
    59
	{
pred@2009
    60
		DBInfo = dbi->FindDatabaseConf("default");
pred@2009
    61
pred@2009
    62
		if (DBInfo == NULL)
pred@2009
    63
		{
kyle@3804
    64
			DBInfo = dbi->FindDatabaseConf("storage-local");
pred@2009
    65
		}
pred@2009
    66
	}
kyle@3804
    67
	
kyle@3804
    68
	if (DBInfo == NULL)
kyle@3804
    69
	{
kyle@3804
    70
		snprintf(error, maxlength, "Could not find any suitable database configs");
kyle@3804
    71
		return false;
kyle@3804
    72
	}
pred@2009
    73
kyle@3804
    74
	if (DBInfo->driver && DBInfo->driver[0] != '\0')
pred@2009
    75
	{
pred@2009
    76
		Driver = dbi->FindOrLoadDriver(DBInfo->driver);
pred@2009
    77
	}
pred@2009
    78
	else
pred@2009
    79
	{
pred@2009
    80
		Driver = dbi->GetDefaultDriver();
pred@2009
    81
	}
pred@2009
    82
pred@2009
    83
	if (Driver == NULL)
pred@2009
    84
	{
pred@2009
    85
		snprintf(error, maxlength, "Could not load DB Driver \"%s\"", DBInfo->driver);
pred@2009
    86
		return false;
pred@2009
    87
	}
pred@2009
    88
pred@2207
    89
	databaseLoading = true;
pred@2207
    90
	TQueryOp *op = new TQueryOp(Query_Connect, 0);
pred@2207
    91
	dbi->AddToThreadQueue(op, PrioQueue_High);
pred@2009
    92
dvander@2135
    93
	dbi->AddDependency(myself, Driver);
dvander@2135
    94
pred@2009
    95
	sharesys->AddNatives(myself, g_ClientPrefNatives);
pred@2009
    96
	sharesys->RegisterLibrary(myself, "clientprefs");
skamonkey@3573
    97
	identity = sharesys->CreateIdentity(sharesys->CreateIdentType("ClientPrefs"), this);
pred@2048
    98
	g_CookieManager.cookieDataLoadedForward = forwards->CreateForward("OnClientCookiesCached", ET_Ignore, 1, NULL, Param_Cell);
pred@2009
    99
pred@2009
   100
	g_CookieType = handlesys->CreateType("Cookie", 
pred@2009
   101
		&g_CookieTypeHandler, 
pred@2009
   102
		0, 
pred@2009
   103
		NULL, 
pred@2009
   104
		NULL, 
pred@2009
   105
		myself->GetIdentity(), 
pred@2009
   106
		NULL);
pred@2009
   107
pred@2048
   108
	g_CookieIterator = handlesys->CreateType("CookieIterator", 
pred@2048
   109
		&g_CookieIteratorHandler, 
pred@2048
   110
		0, 
pred@2048
   111
		NULL, 
pred@2048
   112
		NULL, 
pred@2048
   113
		myself->GetIdentity(), 
pred@2048
   114
		NULL);
pred@2048
   115
pred@2048
   116
	IMenuStyle *style = menus->GetDefaultStyle();
skamonkey@3573
   117
	g_CookieManager.clientMenu = style->CreateMenu(&g_Handler, identity);
pred@2048
   118
	g_CookieManager.clientMenu->SetDefaultTitle("Client Settings:");
pred@2048
   119
pred@2048
   120
	plsys->AddPluginsListener(&g_CookieManager);
pred@2048
   121
pred@2048
   122
	phrases = translator->CreatePhraseCollection();
pred@2048
   123
	phrases->AddPhraseFile("clientprefs.phrases");
pred@2048
   124
	phrases->AddPhraseFile("common.phrases");
pred@2048
   125
pred@2666
   126
	if (late)
pred@2666
   127
	{
kyle@3804
   128
		this->CatchLateLoadClients();
pred@2666
   129
	}
pred@2666
   130
pred@2009
   131
	return true;
pred@2009
   132
}
pred@2009
   133
pred@2009
   134
void ClientPrefs::SDK_OnAllLoaded()
pred@2009
   135
{
pred@2009
   136
	playerhelpers->AddClientListener(&g_CookieManager);
pred@2009
   137
}
pred@2009
   138
dvander@2135
   139
bool ClientPrefs::QueryInterfaceDrop(SMInterface *pInterface)
dvander@2135
   140
{
dvander@2135
   141
	if ((void *)pInterface == (void *)(Database->GetDriver()))
dvander@2135
   142
	{
dvander@2135
   143
		return false;
dvander@2135
   144
	}
dvander@2135
   145
dvander@2135
   146
	return true;
dvander@2135
   147
}
dvander@2135
   148
dvander@2135
   149
void ClientPrefs::NotifyInterfaceDrop(SMInterface *pInterface)
dvander@2135
   150
{
dvander@2135
   151
	if (Database != NULL && (void *)pInterface == (void *)(Database->GetDriver()))
dvander@2135
   152
	{
dvander@2135
   153
		Database->Close();
dvander@2135
   154
		Database = NULL;
dvander@2135
   155
	}
dvander@2135
   156
}
dvander@2135
   157
pred@2009
   158
void ClientPrefs::SDK_OnUnload()
pred@2009
   159
{
pred@2009
   160
	handlesys->RemoveType(g_CookieType, myself->GetIdentity());
pred@2131
   161
	handlesys->RemoveType(g_CookieIterator, myself->GetIdentity());
pred@2009
   162
pred@2009
   163
	g_CookieManager.Unload();
pred@2009
   164
dvander@2135
   165
	if (Database != NULL)
dvander@2135
   166
	{
dvander@2135
   167
		Database->Close();
kyle@3804
   168
		Database = NULL;
kyle@3804
   169
	}
kyle@3804
   170
kyle@3804
   171
	if (g_CookieManager.cookieDataLoadedForward != NULL)
kyle@3804
   172
	{
kyle@3804
   173
		forwards->ReleaseForward(g_CookieManager.cookieDataLoadedForward);
kyle@3804
   174
		g_CookieManager.cookieDataLoadedForward = NULL;
dvander@2135
   175
	}
pred@2009
   176
kyle@3804
   177
	if (g_CookieManager.clientMenu != NULL)
skamonkey@3573
   178
	{
kyle@3804
   179
		Handle_t menuHandle = g_CookieManager.clientMenu->GetHandle();
kyle@3804
   180
		
kyle@3804
   181
		if (menuHandle != BAD_HANDLE)
kyle@3804
   182
		{
kyle@3804
   183
			HandleSecurity sec = HandleSecurity(identity, identity);
kyle@3804
   184
			HandleError err = handlesys->FreeHandle(menuHandle, &sec);
kyle@3804
   185
			if (HandleError_None != err)
kyle@3804
   186
			{
kyle@3804
   187
				g_pSM->LogError(myself, "Error %d when attempting to free client menu handle", err);
kyle@3804
   188
			}
kyle@3804
   189
		}
kyle@3804
   190
		
kyle@3804
   191
		g_CookieManager.clientMenu = NULL;
skamonkey@3573
   192
	}
pred@2131
   193
kyle@3804
   194
	if (phrases != NULL)
kyle@3804
   195
	{
kyle@3804
   196
		phrases->Destroy();
kyle@3804
   197
		phrases = NULL;
kyle@3804
   198
	}
skamonkey@3573
   199
pred@2131
   200
	plsys->RemovePluginsListener(&g_CookieManager);
pred@2131
   201
	playerhelpers->RemoveClientListener(&g_CookieManager);
pred@2207
   202
pred@2207
   203
	queryMutex->DestroyThis();
pred@2207
   204
	cookieMutex->DestroyThis();
pred@2207
   205
}
pred@2207
   206
asherkin@3500
   207
void ClientPrefs::OnCoreMapStart(edict_t *pEdictList, int edictCount, int clientMax)
asherkin@3500
   208
{
kyle@3804
   209
	this->AttemptReconnection();
kyle@3804
   210
}
kyle@3804
   211
kyle@3804
   212
void ClientPrefs::AttemptReconnection()
kyle@3804
   213
{
kyle@3804
   214
	if (Database || databaseLoading)
asherkin@3500
   215
	{
kyle@3804
   216
		return; /* We're already loading, or have loaded. */
asherkin@3500
   217
	}
kyle@3804
   218
	
kyle@3804
   219
	g_pSM->LogMessage(myself, "Attempting to reconnect to database...");
kyle@3804
   220
	databaseLoading = true;
kyle@3804
   221
	
kyle@3804
   222
	TQueryOp *op = new TQueryOp(Query_Connect, 0);
kyle@3804
   223
	dbi->AddToThreadQueue(op, PrioQueue_High);
kyle@3804
   224
	
kyle@3804
   225
	this->CatchLateLoadClients(); /* DB reconnection, we should check if we missed anyone... */
asherkin@3500
   226
}
asherkin@3500
   227
pred@2207
   228
void ClientPrefs::DatabaseConnect()
pred@2207
   229
{
pred@2207
   230
	char error[256];
pred@2207
   231
	int errCode = 0;
pred@2207
   232
pred@2207
   233
	Database = Driver->Connect(DBInfo, true, error, sizeof(error));
pred@2207
   234
pred@2207
   235
	if (Database == NULL)
pred@2207
   236
	{
pred@2207
   237
		g_pSM->LogError(myself, error);
pred@2207
   238
		databaseLoading = false;
pred@2207
   239
		return;
pred@2207
   240
	}
pred@2207
   241
pred@2207
   242
	const char *identifier = Driver->GetIdentifier();
pred@2207
   243
pred@2207
   244
	if (strcmp(identifier, "sqlite") == 0)
pred@2207
   245
	{
dvander@2373
   246
		g_DriverType = Driver_SQLite;
pred@2207
   247
dvander@2338
   248
		if (!Database->DoSimpleQuery(
pred@2207
   249
				"CREATE TABLE IF NOT EXISTS sm_cookies  \
pred@2207
   250
				( \
pred@2207
   251
					id INTEGER PRIMARY KEY AUTOINCREMENT, \
pred@2207
   252
					name varchar(30) NOT NULL UNIQUE, \
pred@2207
   253
					description varchar(255), \
pred@2207
   254
					access INTEGER \
dvander@2338
   255
				)"))
pred@2220
   256
		{
dvander@2338
   257
			g_pSM->LogMessage(myself, "Failed to CreateTable sm_cookies: %s", Database->GetError());
dvander@2338
   258
			goto fatal_fail;
pred@2220
   259
		}
pred@2220
   260
dvander@2338
   261
		if (!Database->DoSimpleQuery(
pred@2207
   262
				"CREATE TABLE IF NOT EXISTS sm_cookie_cache \
pred@2207
   263
				( \
pred@2207
   264
					player varchar(65) NOT NULL, \
pred@2207
   265
					cookie_id int(10) NOT NULL, \
pred@2207
   266
					value varchar(100), \
pred@2207
   267
					timestamp int, \
pred@2207
   268
					PRIMARY KEY (player, cookie_id) \
dvander@2338
   269
				)"))
pred@2220
   270
		{
dvander@2338
   271
			g_pSM->LogMessage(myself, "Failed to CreateTable sm_cookie_cache: %s", Database->GetError());
dvander@2338
   272
			goto fatal_fail;
pred@2220
   273
		}
pred@2207
   274
	}
pred@2207
   275
	else if (strcmp(identifier, "mysql") == 0)
pred@2207
   276
	{
dvander@2373
   277
		g_DriverType = Driver_MySQL;
pred@2207
   278
dvander@2338
   279
		if (!Database->DoSimpleQuery(
pred@2207
   280
				"CREATE TABLE IF NOT EXISTS sm_cookies \
pred@2207
   281
				( \
pred@2207
   282
					id INTEGER unsigned NOT NULL auto_increment, \
pred@2207
   283
					name varchar(30) NOT NULL UNIQUE, \
pred@2207
   284
					description varchar(255), \
pred@2207
   285
					access INTEGER, \
pred@2207
   286
					PRIMARY KEY (id) \
dvander@2338
   287
				)"))
pred@2220
   288
		{
dvander@2338
   289
			g_pSM->LogMessage(myself, "Failed to CreateTable sm_cookies: %s", Database->GetError());
dvander@2338
   290
			goto fatal_fail;
pred@2220
   291
		}
pred@2220
   292
dvander@2338
   293
		if (!Database->DoSimpleQuery(
pred@2207
   294
				"CREATE TABLE IF NOT EXISTS sm_cookie_cache \
pred@2207
   295
				( \
pred@2207
   296
					player varchar(65) NOT NULL, \
pred@2207
   297
					cookie_id int(10) NOT NULL, \
pred@2207
   298
					value varchar(100), \
pred@2207
   299
					timestamp int NOT NULL, \
pred@2207
   300
					PRIMARY KEY (player, cookie_id) \
dvander@2338
   301
				)"))
pred@2220
   302
		{
dvander@2338
   303
			g_pSM->LogMessage(myself, "Failed to CreateTable sm_cookie_cache: %s", Database->GetError());
dvander@2338
   304
			goto fatal_fail;
pred@2220
   305
		}
pred@2207
   306
	}
pred@2207
   307
	else
pred@2207
   308
	{
pred@2207
   309
		g_pSM->LogError(myself, "Unsupported driver \"%s\"", identifier);
dvander@2338
   310
		goto fatal_fail;
pred@2207
   311
	}
pred@2207
   312
pred@2207
   313
	databaseLoading = false;
pred@2207
   314
kyle@3804
   315
	this->ProcessQueryCache();	
pred@2207
   316
	return;
dvander@2338
   317
dvander@2338
   318
fatal_fail:
dvander@2338
   319
	Database->Close();
dvander@2338
   320
	Database = NULL;
dvander@2338
   321
	databaseLoading = false;
pred@2207
   322
}
pred@2207
   323
pred@2207
   324
bool ClientPrefs::AddQueryToQueue( TQueryOp *query )
pred@2207
   325
{
pred@2207
   326
	queryMutex->Lock();
kyle@3804
   327
	if (Database == NULL)
pred@2207
   328
	{
pred@2207
   329
		cachedQueries.push_back(query);
pred@2207
   330
		queryMutex->Unlock();
kyle@3804
   331
		return false;
kyle@3804
   332
	}
kyle@3804
   333
	
kyle@3804
   334
	if (!cachedQueries.empty())
kyle@3804
   335
	{
kyle@3804
   336
		queryMutex->Unlock();
kyle@3804
   337
		this->ProcessQueryCache();
kyle@3804
   338
	}
kyle@3804
   339
	else
kyle@3804
   340
	{
kyle@3804
   341
		queryMutex->Unlock();
pred@2207
   342
	}
pred@2207
   343
kyle@3804
   344
	query->SetDatabase(Database);
kyle@3804
   345
	dbi->AddToThreadQueue(query, PrioQueue_Normal);
kyle@3804
   346
	return true;
pred@2207
   347
}
pred@2207
   348
pred@2207
   349
void ClientPrefs::ProcessQueryCache()
pred@2207
   350
{
kyle@3804
   351
	if (Database == NULL)
kyle@3804
   352
	{
kyle@3804
   353
		return;
kyle@3804
   354
	}
pred@2207
   355
pred@2207
   356
	queryMutex->Lock();
kyle@3804
   357
	TQueryOp *op;
kyle@3804
   358
	for (SourceHook::List<TQueryOp *>::iterator iter = cachedQueries.begin(); iter != cachedQueries.end(); iter++)
pred@2207
   359
	{
kyle@3804
   360
		op = *iter;
kyle@3804
   361
		op->SetDatabase(Database);
kyle@3804
   362
		dbi->AddToThreadQueue(op, PrioQueue_Normal);
pred@2207
   363
	}
pred@2207
   364
pred@2207
   365
	cachedQueries.clear();
pred@2207
   366
	queryMutex->Unlock();
pred@2048
   367
}
pred@2048
   368
datal30mb@3411
   369
size_t IsAuthIdConnected(char *authID)
datal30mb@3411
   370
{
datal30mb@3411
   371
	IGamePlayer *player;
kyle@3804
   372
	const char *authString;
kyle@3804
   373
	
kyle@3804
   374
	for (int playerIndex = playerhelpers->GetMaxClients()+1; --playerIndex > 0;)
datal30mb@3411
   375
	{
datal30mb@3411
   376
		player = playerhelpers->GetGamePlayer(playerIndex);
kyle@3804
   377
		if (player == NULL || !player->IsConnected())
datal30mb@3411
   378
		{
datal30mb@3411
   379
			continue;
datal30mb@3411
   380
		}
kyle@3804
   381
		
kyle@3804
   382
		authString = player->GetAuthString();
kyle@3804
   383
		
kyle@3804
   384
		if (authString == NULL || authString[0] == '\0')
datal30mb@3411
   385
		{
datal30mb@3411
   386
			continue;
datal30mb@3411
   387
		}
datal30mb@3411
   388
datal30mb@3411
   389
		if (strcmp(authString, authID) == 0)
datal30mb@3411
   390
		{
datal30mb@3411
   391
			return playerIndex;
datal30mb@3411
   392
		}
datal30mb@3411
   393
	}
datal30mb@3411
   394
	return 0;
datal30mb@3411
   395
}
datal30mb@3411
   396
kyle@3804
   397
void ClientPrefs::CatchLateLoadClients()
pred@2048
   398
{
kyle@3804
   399
	IGamePlayer *pPlayer;
kyle@3804
   400
	for (int i = playerhelpers->GetMaxClients()+1; --i > 0;)
kyle@3804
   401
	{
kyle@3804
   402
		if (g_CookieManager.AreClientCookiesPening(i) || g_CookieManager.AreClientCookiesCached(i))
kyle@3804
   403
		{
kyle@3804
   404
			continue;
kyle@3804
   405
		}
kyle@3804
   406
	
kyle@3804
   407
		pPlayer = playerhelpers->GetGamePlayer(i);
kyle@3804
   408
kyle@3804
   409
		if (!pPlayer || !pPlayer->IsAuthorized())
kyle@3804
   410
		{
kyle@3804
   411
			continue;
kyle@3804
   412
		}
pred@2048
   413
kyle@3804
   414
		g_CookieManager.OnClientAuthorized(i, pPlayer->GetAuthString());
pred@2048
   415
	}
kyle@3804
   416
}
kyle@3804
   417
kyle@3804
   418
void ClientPrefs::ClearQueryCache(int serial)
kyle@3804
   419
{
kyle@3804
   420
	queryMutex->Lock();
kyle@3804
   421
kyle@3804
   422
	for (SourceHook::List<TQueryOp *>::iterator iter = cachedQueries.begin(); iter != cachedQueries.end();)
pred@2048
   423
	{
kyle@3804
   424
		TQueryOp *op = *iter;
kyle@3804
   425
		if (op && op->PullQueryType() == Query_SelectData && op->PullQuerySerial() == serial)
kyle@3804
   426
 		{
kyle@3804
   427
			op->Destroy();
kyle@3804
   428
			iter = cachedQueries.erase(iter);
kyle@3804
   429
 		}
kyle@3804
   430
 		else
kyle@3804
   431
 		{
kyle@3804
   432
			iter++;
kyle@3804
   433
 		}
kyle@3804
   434
 	}
kyle@3804
   435
	queryMutex->Unlock();
pred@2048
   436
}
pred@2048
   437
pred@2048
   438
bool Translate(char *buffer, 
pred@2048
   439
				   size_t maxlength,
pred@2048
   440
				   const char *format,
pred@2048
   441
				   unsigned int numparams,
pred@2048
   442
				   size_t *pOutLength,
pred@2048
   443
				   ...)
pred@2048
   444
{
pred@2048
   445
	va_list ap;
pred@2048
   446
	unsigned int i;
pred@2048
   447
	const char *fail_phrase;
pred@2048
   448
	void *params[MAX_TRANSLATE_PARAMS];
pred@2048
   449
pred@2048
   450
	if (numparams > MAX_TRANSLATE_PARAMS)
pred@2048
   451
	{
pred@2048
   452
		assert(false);
pred@2048
   453
		return false;
pred@2048
   454
	}
pred@2048
   455
pred@2048
   456
	va_start(ap, pOutLength);
pred@2048
   457
	for (i = 0; i < numparams; i++)
pred@2048
   458
	{
pred@2048
   459
		params[i] = va_arg(ap, void *);
pred@2048
   460
	}
pred@2048
   461
	va_end(ap);
pred@2048
   462
pred@2048
   463
	if (!g_ClientPrefs.phrases->FormatString(buffer,
pred@2048
   464
		maxlength, 
pred@2048
   465
		format, 
pred@2048
   466
		params,
pred@2048
   467
		numparams,
pred@2048
   468
		pOutLength,
pred@2048
   469
		&fail_phrase))
pred@2048
   470
	{
pred@2048
   471
		if (fail_phrase != NULL)
pred@2048
   472
		{
pred@2048
   473
			g_pSM->LogError(myself, "[SM] Could not find core phrase: %s", fail_phrase);
pred@2048
   474
		}
pred@2048
   475
		else
pred@2048
   476
		{
pred@2048
   477
			g_pSM->LogError(myself, "[SM] Unknown fatal error while translating a core phrase.");
pred@2048
   478
		}
pred@2048
   479
pred@2048
   480
		return false;
pred@2048
   481
	}
pred@2048
   482
pred@2048
   483
	return true;
pred@2009
   484
}
pred@2009
   485
kyle@3804
   486
char * UTIL_strncpy(char * destination, const char * source, size_t num)
kyle@3804
   487
{
kyle@3804
   488
	if (source == NULL)
kyle@3804
   489
	{
kyle@3804
   490
		destination[0] = '\0';
kyle@3804
   491
		return destination;
kyle@3804
   492
	}
kyle@3804
   493
	
kyle@3804
   494
	size_t req = strlen(source);
kyle@3804
   495
	if (!req)
kyle@3804
   496
	{
kyle@3804
   497
		destination[0] = '\0';
kyle@3804
   498
		return destination;
kyle@3804
   499
	}
kyle@3804
   500
	else if (req >= num)
kyle@3804
   501
	{
kyle@3804
   502
		req = num-1;
kyle@3804
   503
	}
kyle@3804
   504
	
kyle@3804
   505
	strncpy(destination, source, req);
kyle@3804
   506
	destination[req] = '\0';
kyle@3804
   507
	return destination;
kyle@3804
   508
}
kyle@3804
   509
skamonkey@3573
   510
IdentityToken_t *ClientPrefs::GetIdentity() const
skamonkey@3573
   511
{
skamonkey@3573
   512
	return identity;
skamonkey@3573
   513
}
skamonkey@3573
   514
dvander@2790
   515
const char *ClientPrefs::GetExtensionVerString()
dvander@2783
   516
{
asherkin@3630
   517
	return SM_VERSION_STRING;
dvander@2783
   518
}
pred@2009
   519
dvander@2790
   520
const char *ClientPrefs::GetExtensionDateString()
dvander@2783
   521
{
dvander@2783
   522
	return SM_BUILD_TIMESTAMP;
dvander@2783
   523
}
pred@2048
   524
kyle@3804
   525
ClientPrefs::ClientPrefs()
kyle@3804
   526
{
kyle@3804
   527
	Driver = NULL;
kyle@3804
   528
	Database = NULL;
kyle@3804
   529
	databaseLoading = false;
kyle@3804
   530
	phrases = NULL;
kyle@3804
   531
	DBInfo = NULL;
kyle@3804
   532
kyle@3804
   533
	cookieMutex = NULL;
kyle@3804
   534
	queryMutex = NULL;
kyle@3804
   535
	identity = NULL;
kyle@3804
   536
}