Exemplo n.º 1
0
/// Get online time.
HK_ERROR HkGetOnLineTime(const wstring &charname, int &iSecs)
{
	wstring wscDir;
	if(!HKHKSUCCESS(HkGetAccountDirName(charname, wscDir)))
		return HKE_CHAR_DOES_NOT_EXIST;

	wstring wscFile;
	HkGetCharFileName(charname, wscFile);

	string scCharFile  = scAcctPath + wstos(wscDir) + "\\" + wstos(wscFile) + ".fl";
	if (HkIsEncoded(scCharFile))
	{
		string scCharFileNew = scCharFile + ".ini";
		if (!flc_decode(scCharFile.c_str(), scCharFileNew.c_str()))
			return HKE_COULD_NOT_DECODE_CHARFILE;

		iSecs = (int)IniGetF(scCharFileNew, "mPlayer", "total_time_played", 0.0f);
		DeleteFile(scCharFileNew.c_str());
	}
	else
	{
		iSecs = (int)IniGetF(scCharFile, "mPlayer", "total_time_played", 0.0f);
	}

	return HKE_OK;
}
Exemplo n.º 2
0
void LoadUserSettings(uint iClientID)
{
	CAccount *acc = Players.FindAccountFromClientID(iClientID);
	wstring wscDir;
	HkGetAccountDirName(acc, wscDir);
	string scUserFile = scAcctPath + wstos(wscDir) + "\\flhookuser.ini";

	// read diemsg settings
	ClientInfo[iClientID].dieMsg = (DIEMSGTYPE)IniGetI(scUserFile, "settings", "DieMsg", DIEMSG_ALL);
	ClientInfo[iClientID].dieMsgSize = (CHATSIZE)IniGetI(scUserFile, "settings", "DieMsgSize", CS_DEFAULT);

	// read chatstyle settings
	ClientInfo[iClientID].chatSize = (CHATSIZE)IniGetI(scUserFile, "settings", "ChatSize", CS_DEFAULT);
	ClientInfo[iClientID].chatStyle = (CHATSTYLE)IniGetI(scUserFile, "settings", "ChatStyle", CST_DEFAULT);

	// read ignorelist
	ClientInfo[iClientID].lstIgnore.clear();
	for(int i = 1; ; i++)
	{
		wstring wscIgnore = IniGetWS(scUserFile, "IgnoreList", itos(i), L"");
		if(!wscIgnore.length())
			break;

		IGNORE_INFO ii;
		ii.wscCharname = GetParam(wscIgnore, ' ', 0);
		ii.wscFlags = GetParam(wscIgnore, ' ', 1);
		ClientInfo[iClientID].lstIgnore.push_back(ii);
	}

}
Exemplo n.º 3
0
	/** Start automatic zone checking */
	void IPBans::AdminCmd_AuthenticateChar(CCmds* cmds, const wstring &wscCharname)
	{
		if (!(cmds->rights & RIGHT_SUPERADMIN))
		{
			cmds->Print(L"ERR No permission\n");
			return;
		}

		// init variables
		char szDataPath[MAX_PATH];
		GetUserDataPath(szDataPath);

		wstring wscDir;
		if (HkGetAccountDirName(wscCharname, wscDir)!=HKE_OK)
		{
			cmds->Print(L"ERR Account not found\n");
			return;
		}

		string scPath = string(szDataPath) + "\\Accts\\MultiPlayer\\" + wstos(wscDir) + "\\authenticated";
		FILE *fTest = fopen(scPath.c_str(), "w");
		if (!fTest)
		{
			cmds->Print(L"ERR Writing authentication file\n");
			return;
		}

		fclose(fTest);
		cmds->Print(L"OK\n");
	}
Exemplo n.º 4
0
bool HkAddCheaterLog(const wstring &wscCharname, const wstring &wscReason)
{
	FILE *f = fopen(("./flhook_logs/flhook_cheaters.log"), "at");
	if(!f)
		return false;

	CAccount *acc = HkGetAccountByCharname(wscCharname);
	wstring wscAccountDir = L"???";
	wstring wscAccountID = L"???";
	if(acc)
	{
		HkGetAccountDirName(acc, wscAccountDir);
		wscAccountID = HkGetAccountID(acc);
	}

	uint iClientID = HkGetClientIdFromCharname(wscCharname);
	wstring wscHostName = L"???";
	wstring wscIp = L"???";
	if(iClientID != -1) 
	{
		wscHostName = ClientInfo[iClientID].wscHostname;
		HkGetPlayerIP(iClientID,wscIp);
	}
	

	time_t tNow = time(0);
	struct tm *stNow = localtime(&tNow);
	fprintf(f, "%.2d/%.2d/%.4d %.2d:%.2d:%.2d Possible cheating detected (%s) by %s(%s)(%s) [%s %s]\n",
		stNow->tm_mon + 1, stNow->tm_mday, stNow->tm_year + 1900, stNow->tm_hour, stNow->tm_min, stNow->tm_sec, wstos(wscReason).c_str(), wstos(wscCharname).c_str(), wstos(wscAccountDir).c_str(), wstos(wscAccountID).c_str(), wstos(wscHostName).c_str(), wstos(wscIp).c_str());
	fclose(f);
	return true;
}
Exemplo n.º 5
0
HK_ERROR HkGetAdmin(const wstring &wscCharname, wstring &wscRights)
{
	wscRights = L"";
	HK_GET_CLIENTID(iClientID, wscCharname);
	CAccount *acc;
	if(iClientID == -1) {
		flstr *str = CreateWString(wscCharname.c_str());
		acc = Players.FindAccountFromCharacterName(*str);
		FreeWString(str);
		if(!acc)
			return HKE_CHAR_DOES_NOT_EXIST;;
	} else {
		acc = Players.FindAccountFromClientID(iClientID);
	}

	wstring wscDir;
	HkGetAccountDirName(acc, wscDir);
	string scAdminFile = scAcctPath + wstos(wscDir) + "\\flhookadmin.ini";

	WIN32_FIND_DATA fd;
	HANDLE hFind = FindFirstFile(scAdminFile.c_str(), &fd);
	if(hFind == INVALID_HANDLE_VALUE)
		return HKE_PLAYER_NO_ADMIN;;

	FindClose(hFind);
	wscRights = stows(IniGetS(scAdminFile, "admin", "rights", ""));

	return HKE_OK;
}
Exemplo n.º 6
0
void LogCheater(uint client, const wstring &reason)
{
	CAccount *acc = Players.FindAccountFromClientID(client);

	if (!HkIsValidClientID(client) || !acc)
	{
		AddLog("ERROR: invalid parameter in log cheater, clientid=%u acc=%08x reason=%s", client, acc, wstos(reason).c_str());
		return;
	}

	//internal log
	string scText = wstos(reason);
	Logging("%s", scText.c_str());

	// Set the kick timer to kick this player. We do this to break potential
	// stack corruption.
	HkDelayedKick(client, 1);

		// Ban the account.
		flstr *flStr = CreateWString(acc->wszAccID);
		Players.BanAccount(*flStr, true);
		FreeWString(flStr);

		// Overwrite the ban file so that it contains the ban reason
		wstring wscDir;
		HkGetAccountDirName(acc, wscDir);
		string scBanPath = scAcctPath + wstos(wscDir) + "\\banned";
		FILE *file = fopen(scBanPath.c_str(), "wb");
		if (file)
		{
			fprintf(file, "Autobanned by Marketfucker\n");
			fclose(file);
		}
}
Exemplo n.º 7
0
bool HkAddConnectLog(uint iClientID, wstring wscReason, ...)
{
	wchar_t wszBuf[1024*8] = L"";
	va_list marker;
	va_start(marker, wscReason);

	_vsnwprintf(wszBuf, (sizeof(wszBuf) / 2) - 1, wscReason.c_str(), marker);

	FILE *f = fopen(("./flhook_logs/flhook_connects.log"), "at");
	if(!f)
		return false;

	const wchar_t *wszCharname = (wchar_t*)Players.GetActiveCharacterName(iClientID);
	if(!wszCharname)
		wszCharname = L"";

	CAccount *acc = Players.FindAccountFromClientID(iClientID);
	wstring wscAccountDir;
	HkGetAccountDirName(acc, wscAccountDir);

	time_t tNow = time(0);
	struct tm *stNow = localtime(&tNow);
	fprintf(f, "%.2d/%.2d/%.4d %.2d:%.2d:%.2d Connect (%s): %s(%s)(%s)\n", stNow->tm_mon + 1, stNow->tm_mday, stNow->tm_year + 1900, stNow->tm_hour, stNow->tm_min, stNow->tm_sec, wstos(wszBuf).c_str(), wstos(wszCharname).c_str(), wstos(wscAccountDir).c_str(), wstos(HkGetAccountID(acc)).c_str());
	fclose(f);
	return true;
}
Exemplo n.º 8
0
HK_ERROR HkGetAccountDirName(const wstring &wscCharname, wstring &wscDir)
{
	HK_GET_CLIENTID(iClientID, wscCharname);
	CAccount *acc;
	if(iClientID != -1)
		acc = Players.FindAccountFromClientID(iClientID);		
	else {
		if(!(acc = HkGetAccountByCharname(wscCharname)))
			return HKE_CHAR_DOES_NOT_EXIST;
	}

	return HkGetAccountDirName(acc, wscDir);
}
Exemplo n.º 9
0
/* copy pasta from playercntl as to provide independance*/
string GetUserFilePath(const wstring &wscCharname, const string &scExtension)
{
	// init variables
	char szDataPath[MAX_PATH];
	GetUserDataPath(szDataPath);
	string scAcctPath = string(szDataPath) + "\\Accts\\MultiPlayer\\";

	wstring wscDir;
	wstring wscFile;
	if (HkGetAccountDirName(wscCharname, wscDir) != HKE_OK)
		return "";
	if (HkGetCharFileName(wscCharname, wscFile) != HKE_OK)
		return "";

	return scAcctPath + wstos(wscDir) + "\\" + wstos(wscFile) + scExtension;
}
Exemplo n.º 10
0
	/// Return true if this client is has a "Authenticated" file in the
	/// account directory indicating that the client can connect even if
	/// they are otherwise on a restricted IP range.
	static bool IsAuthenticated(uint iClientID)
	{
		CAccount *acc = Players.FindAccountFromClientID(iClientID);
		if (!acc)
			return false;

		wstring wscDir; 
		HkGetAccountDirName(acc, wscDir); 
		string scUserFile = scAcctPath + wstos(wscDir) + "\\authenticated";
		FILE* fTest = fopen(scUserFile.c_str(), "r");
		if (!fTest)
			return false;

		fclose(fTest);
		return true;
	}
Exemplo n.º 11
0
/**
Determine the path name of a file in the charname account directory with the
provided extension. The resulting path is returned in the path parameter.
*/
string GetUserFilePath(const wstring &charname)
{
	// init variables
	char datapath[MAX_PATH];
	GetUserDataPath(datapath);
	string scAcctPath = string(datapath) + "\\Accts\\MultiPlayer\\";

	wstring wscDir;
	wstring wscFile;
	if (HkGetAccountDirName(charname, wscDir)!=HKE_OK)
		return "";
	if (HkGetCharFileName(charname, wscFile)!=HKE_OK)
		return "";

	return scAcctPath + wstos(wscDir) + "\\" + wstos(wscFile) + ".fl";
}
Exemplo n.º 12
0
	static bool IsBanned(wstring charname)
	{
		char datapath[MAX_PATH];
		GetUserDataPath(datapath);

		wstring dir;
		HkGetAccountDirName(charname, dir);

		string banfile = string(datapath) + "\\Accts\\MultiPlayer\\" + wstos(dir) + "\\banned";

		// Prevent ships from banned accounts from being moved.
		FILE *f = fopen(banfile.c_str(), "r");
		if (f)
		{
			fclose(f);
			return true;
		}
		return false;
	}
Exemplo n.º 13
0
HK_ERROR HkDelAdmin(const wstring &wscCharname)
{
	HK_GET_CLIENTID(iClientID, wscCharname);
	CAccount *acc;
	if(iClientID == -1) {
		flstr *str = CreateWString(wscCharname.c_str());
		acc = Players.FindAccountFromCharacterName(*str);
		FreeWString(str);
		if(!acc)
			return HKE_CHAR_DOES_NOT_EXIST;;
	} else {
		acc = Players.FindAccountFromClientID(iClientID);
	}

	wstring wscDir;
	HkGetAccountDirName(acc, wscDir);
	string scAdminFile = scAcctPath + wstos(wscDir) + "\\flhookadmin.ini";
	DeleteFile(scAdminFile.c_str());
	return HKE_OK;
}
Exemplo n.º 14
0
void LoadUserCharSettings(uint iClientID)
{
	CAccount *acc = Players.FindAccountFromClientID(iClientID);
	wstring wscDir;
	HkGetAccountDirName(acc, wscDir);
	string scUserFile = scAcctPath + wstos(wscDir) + "\\flhookuser.ini";

	// read autobuy
	wstring wscFilename;
	HkGetCharFileName(ARG_CLIENTID(iClientID), wscFilename);
	string scSection = "autobuy_" + wstos(wscFilename);

	ClientInfo[iClientID].bAutoBuyMissiles = IniGetB(scUserFile, scSection, "missiles", false);
	ClientInfo[iClientID].bAutoBuyMines = IniGetB(scUserFile, scSection, "mines", false);
	ClientInfo[iClientID].bAutoBuyTorps = IniGetB(scUserFile, scSection, "torps", false);
	ClientInfo[iClientID].bAutoBuyCD = IniGetB(scUserFile, scSection, "cd", false);
	ClientInfo[iClientID].bAutoBuyCM = IniGetB(scUserFile, scSection, "cm", false);
	ClientInfo[iClientID].bAutoBuyReload = IniGetB(scUserFile, scSection, "reload", false);

	CALL_PLUGINS(PLUGIN_LoadUserCharSettings,(iClientID));
}
Exemplo n.º 15
0
	/// Set the move char code for all characters in the account
	void Rename::AdminCmd_SetAccMoveCode(CCmds* cmds, const wstring &wscCharname, const wstring &wscCode)
	{
		// Don't indicate an error if moving is disabled.
		if (!set_bEnableMoveChar)
			return;

		if (!(cmds->rights & RIGHT_SUPERADMIN))
		{
			cmds->Print(L"ERR No permission\n");
			return;
		}

		wstring wscDir;
		if (HkGetAccountDirName(wscCharname, wscDir)!=HKE_OK)
		{
			cmds->Print(L"ERR Charname not found\n");
			return;
		}

		if (wscCode.length()==0)
		{
			cmds->Print(L"ERR Code too small, set to none to clear.\n");
			return;
		}

		// Get the account path.
		char szDataPath[MAX_PATH];
		GetUserDataPath(szDataPath);
		string scPath = string(szDataPath) + "\\Accts\\MultiPlayer\\" + wstos(wscDir) + "\\*.fl";

		// Open the directory iterator.
		WIN32_FIND_DATA FindFileData; 
		HANDLE hFileFind = FindFirstFile(scPath.c_str(), &FindFileData);
		if (hFileFind==INVALID_HANDLE_VALUE)
		{
			cmds->Print(L"ERR Account directory not found\n");
			return;
		}

		// Iterate it
		do
		{
			string scCharfile = FindFileData.cFileName;
			string scMoveCodeFile = string(szDataPath) + "\\Accts\\MultiPlayer\\" + wstos(wscDir) + "\\"
				+ scCharfile.substr(0,scCharfile.size()-3) + "-movechar.ini";
			if (wscCode==L"none")
			{
				IniWriteW(scMoveCodeFile, "Settings", "Code", L"");
				cmds->Print(L"OK Movechar code cleared on "+stows(scCharfile)+L"\n");
			}
			else
			{
				IniWriteW(scMoveCodeFile, "Settings", "Code", wscCode);
				cmds->Print(L"OK Movechar code set to "+wscCode +L" on "+stows(scCharfile)+L"\n");
			}
		}
		while (FindNextFile(hFileFind, &FindFileData));
		FindClose(hFileFind); 

		cmds->Print(L"OK\n");
	}
Exemplo n.º 16
0
	/**
	 Move a character from a remote account into this one.
	*/
	bool Rename::UserCmd_MoveChar(uint iClientID, const wstring &wscCmd, const wstring &wscParam, const wchar_t *usage)
	{
		HK_ERROR err;

		// Don't indicate an error if moving is disabled.
		if (!set_bEnableMoveChar)
			return false;

		// Indicate an error if the command does not appear to be formatted correctly 
		// and stop processing but tell FLHook that we processed the command.
		if (wscParam.size()==0)
		{
			PrintUserCmdText(iClientID, L"ERR Invalid parameters");
			PrintUserCmdText(iClientID, usage);
			return true;
		}

		uint iBaseID;
		pub::Player::GetBase(iClientID, iBaseID);
		if (!iBaseID)
		{
			PrintUserCmdText(iClientID, L"ERR Not in base");
			return true;
		}

		// Get the target account directory.
		string scFile;
		wstring wscMovingCharname = Trim(GetParam(wscParam, L' ', 0));
		if (!GetUserFilePath(scFile, wscMovingCharname, "-movechar.ini"))
		{
			PrintUserCmdText(iClientID, L"ERR Character does not exist");
			return true;
		}
		
		// Check the move char code.
		wstring wscCode = Trim(GetParam(wscParam, L' ', 1));
		wstring wscTargetCode = IniGetWS(scFile, "Settings", "Code", L"");
		if (!wscTargetCode.length() || wscTargetCode!=wscCode)
		{
			PrintUserCmdText(iClientID, L"ERR Move character access denied");
			return true;
		}

		// Get the character name for this connection.
		wstring wscCharname = (const wchar_t*)Players.GetActiveCharacterName(iClientID);

		for (map<wstring, LockedShipsStruct>::iterator i = MapLockedShips.begin(); i != MapLockedShips.end(); ++i)
		{
			if ((i->first == wscMovingCharname) && (i->second.LockLevel > 0))
			{
				PrintUserCmdText(iClientID, L"ERR This ship is locked. The FBI has been notified.");
				wstring spurdoip;
				HkGetPlayerIP(iClientID, spurdoip);
				AddLog("SHIPLOCK: Attempt to movechar locked ship %s from IP %s", wstos(wscMovingCharname).c_str(), wstos(spurdoip).c_str());
				ConPrint(L"SHIPLOCK: Attempt to movechar locked ship %s from IP %s\n", wscMovingCharname.c_str(), spurdoip.c_str());
				return true;
			}
		}

		// Prevent ships from banned accounts from being moved.
		if (IsBanned(wscMovingCharname))
		{
			PrintUserCmdText(iClientID, L"ERR not permitted");
			return true;
		}
		// Saving the characters forces an anti-cheat checks and fixes 
		// up a multitude of other problems.
		HkSaveChar(wscCharname);
		HkSaveChar(wscMovingCharname);

		// Read the current number of credits for the player
		// and check that the character has enough cash.
		int iCash = 0;
		if ((err = HkGetCash(wscCharname, iCash)) != HKE_OK)
		{
			PrintUserCmdText(iClientID, L"ERR "+HkErrGetText(err));
			return true;
		}
		if (set_iMoveCost>0 && iCash<set_iMoveCost)
		{
			PrintUserCmdText(iClientID, L"ERR Insufficient credits");
			return true;
		}

		// Check there is room in this account.
		CAccount *acc=Players.FindAccountFromClientID(iClientID);
		if (acc->iNumberOfCharacters >= 7)
		{
			PrintUserCmdText(iClientID, L"ERR Too many characters in account");
			return true;
		}

		// Copy character file into this account with a temp name.
		char szDataPath[MAX_PATH];
		GetUserDataPath(szDataPath);
		string scAcctPath = string(szDataPath) + "\\Accts\\MultiPlayer\\";

		wstring wscDir;
		wstring wscSourceDir;
		wstring wscSourceFile;
		if ((err = HkGetAccountDirName(wscCharname, wscDir))!=HKE_OK)
		{
			PrintUserCmdText(iClientID, L"ERR "+HkErrGetText(err));
			return true;
		}
		if ((err = HkGetAccountDirName(wscMovingCharname, wscSourceDir))!=HKE_OK)
		{
			PrintUserCmdText(iClientID, L"ERR "+HkErrGetText(err));
			return true;
		}
		if ((err = HkGetCharFileName(wscMovingCharname, wscSourceFile))!=HKE_OK)
		{
			PrintUserCmdText(iClientID, L"ERR "+HkErrGetText(err));
			return true;
		}

		// Remove cash if we're charging for it.
		if (set_iMoveCost>0)
			HkAddCash(wscCharname, 0-set_iMoveCost);
		HkSaveChar(wscCharname);
		
		// Schedule the move
		MOVE o;
		o.wscDestinationCharname = wscCharname;
		o.wscMovingCharname = wscMovingCharname;
		o.scSourceFile = scAcctPath + wstos(wscSourceDir) + "\\" + wstos(wscSourceFile) + ".fl";
		o.scDestFile = scAcctPath + wstos(wscDir) + "\\" + wstos(wscSourceFile) + ".fl";
		o.scDestFileTemp = scAcctPath + wstos(wscDir) + "\\" + wstos(wscSourceFile) + ".fl.moving";
		pendingMoves.push_back(o);

		// Delete the move code
		::DeleteFileA(scFile.c_str());

		// Kick
		HkKickReason(o.wscDestinationCharname, L"Moving character, please wait 10 seconds before reconnecting");
		HkKickReason(o.wscMovingCharname, L"Moving character, please wait 10 seconds before reconnecting");
		return true;
	}
Exemplo n.º 17
0
	bool UserCmd_RenameMe(uint iClientID, const wstring &wscCmd, const wstring &wscParam, const wchar_t *usage)
	{
		HK_ERROR err;

		// Don't indicate an error if moving is disabled.
		if (!set_bEnableRenameMe)
			return false;

		// Indicate an error if the command does not appear to be formatted correctly 
		// and stop processing but tell FLHook that we processed the command.
		if (wscParam.size()==0)
		{
			PrintUserCmdText(iClientID, L"ERR Invalid parameters");
			PrintUserCmdText(iClientID, usage);
			return true;
		}

		uint iBaseID;
		pub::Player::GetBase(iClientID, iBaseID);
		if (!iBaseID)
		{
			PrintUserCmdText(iClientID, L"ERR Not in base");
			return true;
		}

		// If the new name contains spaces then flag this as an
		// error.
		wstring wscNewCharname = Trim(GetParam(wscParam, L' ', 0));

		// Get the character name for this connection.
		wstring wscCharname = (const wchar_t*)Players.GetActiveCharacterName(iClientID);

		for (map<wstring, LockedShipsStruct>::iterator i = MapLockedShips.begin(); i != MapLockedShips.end(); ++i)
		{
			if ((i->first == wscCharname) && (i->second.LockLevel > 0))
			{
				PrintUserCmdText(iClientID, L"ERR This ship is locked. The FBI has been notified.");
				wstring spurdoip;
				HkGetPlayerIP(iClientID, spurdoip);
				AddLog("SHIPLOCK: Attempt to rename locked ship %s from IP %s", wstos(wscCharname).c_str(), wstos(spurdoip).c_str());
				ConPrint(L"SHIPLOCK: Attempt to rename locked ship %s from IP %s\n", wscCharname.c_str(), spurdoip.c_str());
				return true;
			}
		}

		if (wscNewCharname.find(L" ")!=-1)
		{
			PrintUserCmdText(iClientID, L"ERR Space characters not allowed in name");
			return true;
		}

		if (HkGetAccountByCharname(wscNewCharname))
		{
			PrintUserCmdText(iClientID, L"ERR Name already exists");	
			return true;
		}

		if (wscNewCharname.length() > 23)
		{
			PrintUserCmdText(iClientID, L"ERR Name to long");	
			return true;
		}
		
		if (wscNewCharname.length() < MIN_CHAR_TAG_LEN)
		{
			PrintUserCmdText(iClientID, L"ERR Name to short");	
			return true;
		}

		if (set_bCharnameTags)
		{
			wstring wscPassword = Trim(GetParam(wscParam, L' ', 1));

			for (std::map<wstring, TAG_DATA>::iterator i = mapTagToPassword.begin(); i != mapTagToPassword.end(); ++i)
			{
				if (wscNewCharname.find(i->first)==0
					&& i->second.rename_password.size() != 0)
				{
					if (!wscPassword.length())
					{
						PrintUserCmdText(iClientID, L"ERR Name starts with an owned tag. Password is required.");	
						return true;
					}
					else if (wscPassword != i->second.master_password
						&& wscPassword != i->second.rename_password)
					{
						PrintUserCmdText(iClientID, L"ERR Name starts with an owned tag. Password is wrong.");	
						return true;
					}
					// Password is valid for owned tag.
					break;
				}
			}
		}

		// Saving the characters forces an anti-cheat checks and fixes 
		// up a multitude of other problems.
		HkSaveChar(wscCharname);
		if (!HkIsValidClientID(iClientID))
			return true;

		// Read the current number of credits for the player
		// and check that the character has enough cash.
		int iCash = 0;
		if ((err = HkGetCash(wscCharname, iCash)) != HKE_OK)
		{
			PrintUserCmdText(iClientID, L"ERR "+HkErrGetText(err));
			return true;
		}
		if (set_iRenameCost>0 && iCash<set_iRenameCost)
		{
			PrintUserCmdText(iClientID, L"ERR Insufficient credits");
			return true;
		}

		// Read the last time a rename was done on this character
		wstring wscDir;
		if ((err = HkGetAccountDirName(wscCharname, wscDir))!=HKE_OK)
		{
			PrintUserCmdText(iClientID, L"ERR "+HkErrGetText(err));
			return true;
		}
		string scRenameFile  = scAcctPath + wstos(wscDir) + "\\" + "rename.ini";
		int lastRenameTime = IniGetI(scRenameFile, "General", wstos(wscCharname), 0);

		// If a rename was done recently by this player then reject the request.
		// I know that time() returns time_t...shouldn't matter for a few years
		// yet.
		if ((lastRenameTime + 300) < (int)time(0))
		{
			if ((lastRenameTime + set_iRenameTimeLimit) > (int)time(0))
			{
				PrintUserCmdText(iClientID, L"ERR Rename time limit");
				return true;
			}
		}

		char szDataPath[MAX_PATH];
		GetUserDataPath(szDataPath);
		string scAcctPath = string(szDataPath) + "\\Accts\\MultiPlayer\\";

		wstring wscSourceFile;
		if ((err = HkGetCharFileName(wscCharname, wscSourceFile))!=HKE_OK)
		{
			PrintUserCmdText(iClientID, L"ERR "+HkErrGetText(err));
			return true;
		}
		wstring wscDestFile;
		if ((err = HkGetCharFileName(wscNewCharname, wscDestFile))!=HKE_OK)
		{
			PrintUserCmdText(iClientID, L"ERR "+HkErrGetText(err));
			return true;
		}

		// Remove cash if we're charging for it.
		if (set_iRenameCost>0)
			HkAddCash(wscCharname, 0-set_iRenameCost);


		RENAME o;
		o.wscCharname = wscCharname;
		o.wscNewCharname = wscNewCharname;
		o.scSourceFile = scAcctPath + wstos(wscDir) + "\\" + wstos(wscSourceFile) + ".fl";
		o.scDestFile = scAcctPath + wstos(wscDir) + "\\" + wstos(wscDestFile) + ".fl";
		o.scDestFileTemp = scAcctPath + wstos(wscDir) + "\\" + wstos(wscSourceFile) + ".fl.renaming";
		pendingRenames.push_back(o);
		
		HkKickReason(o.wscCharname, L"Updating character, please wait 10 seconds before reconnecting");
		IniWrite(scRenameFile, "General", wstos(o.wscNewCharname), itos((int)time(0)));
		return true;
	}