Go Back   EQEmulator Home > EQEmulator Forums > Development > Development::Development

Development::Development Forum for development topics and for those interested in EQEMu development. (Not a support forum)

 
 
Thread Tools Display Modes
Prev Previous Post   Next Post Next
  #2  
Old 04-17-2010, 11:12 AM
Angelox
AX Classic Developer
 
Join Date: May 2006
Location: filler
Posts: 2,049
Default

Note; if you have an account on your server on one lsaccount table, but the second lsaccount table is still empty, when you access the empty one for the first time, you will get bumped back to LS while it makes the account ID. after that, it works fine.
EqEmuConfig.cpp
Code:
#include "../common/debug.h"
#include "EQEmuConfig.h"
#include "MiscFunctions.h"
#include <iostream>
string EQEmuConfig::ConfigFile = "eqemu_config.xml";
EQEmuConfig *EQEmuConfig::_config = NULL;

void EQEmuConfig::do_world(TiXmlElement *ele) {
	const char *text;
	TiXmlElement * sub_ele;;

	text= ParseTextBlock(ele,"shortname");
	if (text)
		ShortName=text;

	text = ParseTextBlock(ele,"longname");
	if (text)
		LongName=text;

	text = ParseTextBlock(ele,"address",true);
	if (text)
		WorldAddress=text;

	text = ParseTextBlock(ele,"localaddress",true);
	if (text)
		LocalAddress=text;

	text = ParseTextBlock(ele,"maxclients",true);
	if (text)
		MaxClients=atoi(text);

	// Get the <key> element
	text = ParseTextBlock(ele,"key",true);
	if (text)
		SharedKey=text;

	// Get the <loginserver> element
	sub_ele = ele->FirstChildElement("loginserver");
	if (sub_ele) {
		text=ParseTextBlock(sub_ele,"host",true);
		if (text)
			LoginHost=text;

		text=ParseTextBlock(sub_ele,"port",true);
		if (text)
			LoginPort=atoi(text);
		
		text=ParseTextBlock(sub_ele,"account",true);
		if (text)
			LoginAccount=text;

		text=ParseTextBlock(sub_ele,"password",true);
		if (text)
			LoginPassword=text;

#ifdef DUAL_SERVER
		text=ParseTextBlock(sub_ele,"host2",true);
		if (text)
			LoginHost2=text;

		text=ParseTextBlock(sub_ele,"port2",true);
		if (text)
			LoginPort2=atoi(text);
		
		text=ParseTextBlock(sub_ele,"account2",true);
		if (text)
			LoginAccount2=text;

		text=ParseTextBlock(sub_ele,"password2",true);
		if (text)
			LoginPassword2=text;
#endif

	}
	
	// Check for locked
	sub_ele = ele->FirstChildElement("locked");
	if (sub_ele != NULL)
		Locked=true;

	// Get the <tcp> element
	sub_ele = ele->FirstChildElement("tcp");
	if(sub_ele != NULL) {

		text = sub_ele->Attribute("ip");
		if (text)
			WorldIP=text;

		text = sub_ele->Attribute("port");
		if (text)
			WorldTCPPort=atoi(text);

		text = sub_ele->Attribute("telnet");
		if (text && !strcasecmp(text,"enabled"))
			TelnetEnabled=true;

	}

	// Get the <http> element
	sub_ele = ele->FirstChildElement("http");
	if(sub_ele != NULL) {

//		text = sub_ele->Attribute("ip");
//		if (text)
//			WorldIP=text;

		text = sub_ele->Attribute("mimefile");
		if (text)
			WorldHTTPMimeFile=text;

		text = sub_ele->Attribute("port");
		if (text)
			WorldHTTPPort=atoi(text);

		text = sub_ele->Attribute("enabled");
		if (text && !strcasecmp(text,"true"))
			WorldHTTPEnabled=true;
		
	}
}

void EQEmuConfig::do_chatserver(TiXmlElement *ele) {
	const char *text;

	text=ParseTextBlock(ele,"host",true);
	if (text)
		ChatHost=text;

	text=ParseTextBlock(ele,"port",true);
	if (text)
		ChatPort=atoi(text);
}
		
void EQEmuConfig::do_mailserver(TiXmlElement *ele) {
	const char *text;

	text=ParseTextBlock(ele,"host",true);
	if (text)
		MailHost=text;

	text=ParseTextBlock(ele,"port",true);
	if (text)
		MailPort=atoi(text);
}
		
void EQEmuConfig::do_database(TiXmlElement *ele) {
	const char *text;

	text=ParseTextBlock(ele,"host",true);
	if (text)
		DatabaseHost=text;

	text=ParseTextBlock(ele,"port",true);
	if (text)
		DatabasePort=atoi(text);

	text=ParseTextBlock(ele,"username",true);
	if (text)
		DatabaseUsername=text;

	text=ParseTextBlock(ele,"password",true);
	if (text)
		DatabasePassword=text;

	text=ParseTextBlock(ele,"db",true);
	if (text)
		DatabaseDB=text;
}
		
void EQEmuConfig::do_zones(TiXmlElement *ele) {
	const char *text;
	TiXmlElement *sub_ele;
//	TiXmlNode *node,*sub_node;

	text=ParseTextBlock(ele,"defaultstatus",true);
	if (text)
		DefaultStatus=atoi(text);

	// Get the <ports> element
	sub_ele = ele->FirstChildElement("ports");
	if(sub_ele != NULL) {

		text = sub_ele->Attribute("low");
		if (text)
			ZonePortLow=atoi(text);;

		text = sub_ele->Attribute("high");
		if (text)
			ZonePortHigh=atoi(text);
	}

/*	node = ele->FirstChild("start");
	if (node) {
		string s_static="static";
		string s_dynamic="dynamic";
		sub_node=NULL;
		while( (sub_node = node->IterateChildren( sub_node )) ) {
			if(sub_node->Type() != TiXmlNode::ELEMENT)
				continue;	//skip crap we dont care about

			TiXmlElement *sub_ele = (TiXmlElement *) sub_node;

			if (s_static == sub_ele->Value()) {
				const char *zone = MakeLowerString(sub_ele->Attribute("zone"));
				const char *port = sub_ele->Attribute("port");
				if (zone) {
					StaticZones[zone] = (port) ? atoi(port) : 0;
				}
			} else if (s_dynamic == sub_ele->Value()) {
				const char *count = sub_ele->Attribute("count");
				if (count) {
					DynamicCount=atoi(count);
				}
			}
		}
	}*/
}

void EQEmuConfig::do_files(TiXmlElement *ele) {
	const char *text;

	text=ParseTextBlock(ele,"spells",true);
	if (text)
		SpellsFile=text;

	text=ParseTextBlock(ele,"opcodes",true);
	if (text)
		OpCodesFile=text;

	text=ParseTextBlock(ele,"logsettings",true);
	if (text)
		LogSettingsFile=text;

	text=ParseTextBlock(ele,"eqtime",true);
	if (text)
		EQTimeFile=text;
}

void EQEmuConfig::do_directories(TiXmlElement *ele) {
	const char *text;

	text=ParseTextBlock(ele,"maps",true);
	if (text)
		MapDir=text;

	text=ParseTextBlock(ele,"quests",true);
	if (text)
		QuestDir=text;

	text=ParseTextBlock(ele,"plugins",true);
	if (text)
		PluginDir=text;

}

void EQEmuConfig::do_launcher(TiXmlElement *ele) {
	const char *text;
	TiXmlElement *sub_ele;

	text=ParseTextBlock(ele,"logprefix",true);
	if (text)
		LogPrefix = text;

	text=ParseTextBlock(ele,"logsuffix",true);
	if (text)
		LogSuffix = text;

	// Get the <exe> element
	text = ParseTextBlock(ele,"exe",true);
	if (text)
		ZoneExe = text;

	// Get the <timers> element
	sub_ele = ele->FirstChildElement("timers");
	if(sub_ele != NULL) {
		text = sub_ele->Attribute("restart");
		if (text)
			RestartWait = atoi(text);

		text = sub_ele->Attribute("reterminate");
		if (text)
			TerminateWait = atoi(text);

		text = sub_ele->Attribute("initial");
		if (text)
			InitialBootWait = atoi(text);

		text = sub_ele->Attribute("interval");
		if (text)
			ZoneBootInterval = atoi(text);
	}
}

string EQEmuConfig::GetByName(const string &var_name) const {
	if(var_name == "ShortName")
		return(ShortName);
	if(var_name == "LongName")
		return(LongName);
	if(var_name == "WorldAddress")
		return(WorldAddress);
	if(var_name == "LoginHost")
		return(LoginHost);
	if(var_name == "LoginAccount")
		return(LoginAccount);
	if(var_name == "LoginPassword")
		return(LoginPassword);
	if(var_name == "LoginPort")
		return(itoa(LoginPort));

#ifdef DUAL_SERVER
	if(var_name == "LoginHost2")
		return(LoginHost2);
	if(var_name == "LoginAccount2")
		return(LoginAccount2);
	if(var_name == "LoginPassword2")
		return(LoginPassword2);
	if(var_name == "LoginPort2")
		return(itoa(LoginPort2));
#endif

	if(var_name == "Locked")
		return(Locked?"true":"false");
	if(var_name == "WorldTCPPort")
		return(itoa(WorldTCPPort));
	if(var_name == "WorldIP")
		return(WorldIP);
	if(var_name == "TelnetEnabled")
		return(TelnetEnabled?"true":"false");
	if(var_name == "WorldHTTPPort")
		return(itoa(WorldHTTPPort));
	if(var_name == "WorldHTTPMimeFile")
		return(WorldHTTPMimeFile);
	if(var_name == "WorldHTTPEnabled")
		return(WorldHTTPEnabled?"true":"false");
	if(var_name == "ChatHost")
		return(ChatHost);
	if(var_name == "ChatPort")
		return(itoa(ChatPort));
	if(var_name == "MailHost")
		return(MailHost);
	if(var_name == "MailPort")
		return(itoa(MailPort));
	if(var_name == "DatabaseHost")
		return(DatabaseHost);
	if(var_name == "DatabaseUsername")
		return(DatabaseUsername);
	if(var_name == "DatabasePassword")
		return(DatabasePassword);
	if(var_name == "DatabaseDB")
		return(DatabaseDB);
	if(var_name == "DatabasePort")
		return(itoa(DatabasePort));
	if(var_name == "SpellsFile")
		return(SpellsFile);
	if(var_name == "OpCodesFile")
		return(OpCodesFile);
	if(var_name == "EQTimeFile")
		return(EQTimeFile);
	if(var_name == "LogSettingsFile")
		return(LogSettingsFile);
	if(var_name == "MapDir")
		return(MapDir);
	if(var_name == "QuestDir")
		return(QuestDir);
	if(var_name == "PluginDir")
		return(PluginDir);
	if(var_name == "LogPrefix")
		return(LogPrefix);
	if(var_name == "LogSuffix")
		return(LogSuffix);
	if(var_name == "ZoneExe")
		return(ZoneExe);
	if(var_name == "ZonePortLow")
		return(itoa(ZonePortLow));
	if(var_name == "ZonePortHigh")
		return(itoa(ZonePortHigh));
	if(var_name == "DefaultStatus")
		return(itoa(DefaultStatus));
//	if(var_name == "DynamicCount")
//		return(itoa(DynamicCount));
	return("");
}

void EQEmuConfig::Dump() const
{
	cout << "ShortName = " << ShortName << endl;
	cout << "LongName = " << LongName << endl;
	cout << "WorldAddress = " << WorldAddress << endl;
	cout << "LoginHost = " << LoginHost << endl;
	cout << "LoginAccount = " << LoginAccount << endl;
	cout << "LoginPassword = " << LoginPassword << endl;
	cout << "LoginPort = " << LoginPort << endl;

#ifdef DUAL_SERVER
	cout << "LoginHost2 = " << LoginHost2 << endl;
	cout << "LoginAccount2 = " << LoginAccount2 << endl;
	cout << "LoginPassword2 = " << LoginPassword2 << endl;
	cout << "LoginPort2 = " << LoginPort2 << endl;
#endif

	cout << "Locked = " << Locked << endl;
	cout << "WorldTCPPort = " << WorldTCPPort << endl;
	cout << "WorldIP = " << WorldIP << endl;
	cout << "TelnetEnabled = " << TelnetEnabled << endl;
	cout << "WorldHTTPPort = " << WorldHTTPPort << endl;
	cout << "WorldHTTPMimeFile = " << WorldHTTPMimeFile << endl;
	cout << "WorldHTTPEnabled = " << WorldHTTPEnabled << endl;
	cout << "ChatHost = " << ChatHost << endl;
	cout << "ChatPort = " << ChatPort << endl;
	cout << "MailHost = " << MailHost << endl;
	cout << "MailPort = " << MailPort << endl;
	cout << "DatabaseHost = " << DatabaseHost << endl;
	cout << "DatabaseUsername = " << DatabaseUsername << endl;
	cout << "DatabasePassword = " << DatabasePassword << endl;
	cout << "DatabaseDB = " << DatabaseDB << endl;
	cout << "DatabasePort = " << DatabasePort << endl;
	cout << "SpellsFile = " << SpellsFile << endl;
	cout << "OpCodesFile = " << OpCodesFile << endl;
	cout << "EQTimeFile = " << EQTimeFile << endl;
	cout << "LogSettingsFile = " << LogSettingsFile << endl;
	cout << "MapDir = " << MapDir << endl;
	cout << "QuestDir = " << QuestDir << endl;
	cout << "PluginDir = " << PluginDir << endl;
	cout << "ZonePortLow = " << ZonePortLow << endl;
	cout << "ZonePortHigh = " << ZonePortHigh << endl;
	cout << "DefaultStatus = " << (int)DefaultStatus << endl;
//	cout << "DynamicCount = " << DynamicCount << endl;
}
EqEmuConfig.h
Code:
#ifndef __EQEmuConfig_H
#define __EQEmuConfig_H

#include "XMLParser.h"

class EQEmuConfig : public XMLParser {
public:
	virtual string GetByName(const string &var_name) const;

	// From <world/>
	string ShortName;
	string LongName;
	string WorldAddress;
	string LocalAddress;
	string LoginHost;
	string LoginAccount;
	string LoginPassword;
	uint16 LoginPort;

#ifdef DUAL_SERVER
	string LoginHost2;
	string LoginAccount2;
	string LoginPassword2;
	uint16 LoginPort2;
#endif

	bool Locked;
	uint16 WorldTCPPort;
	string WorldIP;
	bool TelnetEnabled;
	sint32 MaxClients;
	bool WorldHTTPEnabled;
	uint16 WorldHTTPPort;
	string WorldHTTPMimeFile;
	string SharedKey;
	
	// From <chatserver/>
	string ChatHost;
	uint16 ChatPort;
	
	// From <mailserver/>
	string MailHost;
	uint16 MailPort;

	// From <database/>
	string DatabaseHost;
	string DatabaseUsername;
	string DatabasePassword;
	string DatabaseDB;
	uint16 DatabasePort;

	// From <files/>
	string SpellsFile;
	string OpCodesFile;
	string EQTimeFile;
	string LogSettingsFile;

	// From <directories/>
	string MapDir;
	string QuestDir;
	string PluginDir;
	
	// From <launcher/>
	string LogPrefix;
	string LogSuffix;
	string ZoneExe;
	uint32 RestartWait;
	uint32 TerminateWait;
	uint32 InitialBootWait;
	uint32 ZoneBootInterval;

	// From <zones/>
	uint16 ZonePortLow;
	uint16 ZonePortHigh;
	uint8 DefaultStatus;

//	uint16 DynamicCount;

//	map<string,uint16> StaticZones;
	
protected:

	static EQEmuConfig *_config;

	static string ConfigFile;

#define ELEMENT(name) \
	void do_##name(TiXmlElement *ele);
	#include "EQEmuConfig_elements.h"


	EQEmuConfig() {
		// import the needed handler prototypes
#define ELEMENT(name) \
		Handlers[#name]=(ElementHandler)&EQEmuConfig::do_##name;
	#include "EQEmuConfig_elements.h"

		// Set sane defaults

		// Login server
		LoginHost="eqemulator.net";
		LoginPort=5998;

#ifdef DUAL_SERVER
		LoginHost2="eqemulator.net2";
		LoginPort2=5999;
#endif

		// World
		Locked=false;
		WorldTCPPort=9000;
		TelnetEnabled=false;
		WorldHTTPEnabled=false;
		WorldHTTPPort=9080;
		WorldHTTPMimeFile="mime.types";
		SharedKey = "";	//blank disables authentication

		// Mail
		ChatHost="eqchat.eqemulator.net";
		ChatPort=7778;

		// Mail
		MailHost="eqmail.eqemulator.net";
		MailPort=7779;

		// Mysql
		DatabaseHost="localhost";
		DatabasePort=3306;
		DatabaseUsername="eq";
		DatabasePassword="eq";
		DatabaseDB="eq";

		// Files
		SpellsFile="spells_us.txt";
		OpCodesFile="opcodes.conf";
		EQTimeFile="eqtime.cfg";
		LogSettingsFile="log.ini";

		// Dirs
		MapDir="Maps";
		QuestDir="quests";
		PluginDir="plugins";
		
		// Launcher
		LogPrefix = "logs/zone-";
		LogSuffix = ".log";
		RestartWait = 10000;		//milliseconds
		TerminateWait = 10000;		//milliseconds
		InitialBootWait = 20000;	//milliseconds
		ZoneBootInterval = 2000;	//milliseconds
#ifdef WIN32
		ZoneExe = "zone.exe";
#else
		ZoneExe = "./zone";
#endif
		
		// Zones
		ZonePortLow=7000;
		ZonePortHigh=7999;
		DefaultStatus=0;
		
		// For where zones need to connect to.
		WorldIP="127.0.0.1";
		
		// Dynamics to start
		//DynamicCount=5;
		
		MaxClients=-1;
		
	}
	virtual ~EQEmuConfig() {}

public:

	// Produce a const singleton
	static const EQEmuConfig *get() {
		if (_config == NULL) 
			LoadConfig();
		return(_config);
	}

	// Allow the use to set the conf file to be used.
	static void SetConfigFile(string file) { EQEmuConfig::ConfigFile = file; }

	// Load the config
	static bool LoadConfig() {
		if (_config != NULL)
			delete _config;
		_config=new EQEmuConfig;

		return _config->ParseFile(EQEmuConfig::ConfigFile.c_str(),"server");
	}

	void Dump() const;
};

#endif
TCPConnection.cpp
Code:
#include "../common/debug.h"

#include <iostream>
using namespace std;
#include <string.h>
#include <stdio.h>
#include <iomanip>
using namespace std;

#include "TCPConnection.h"
#include "../common/servertalk.h"
#include "../common/timer.h"
#include "../common/packet_dump.h"

#ifdef FREEBSD //Timothy Whitman - January 7, 2003
	#define MSG_NOSIGNAL 0
#endif

#ifdef WIN32
InitWinsock winsock;
#endif

#define LOOP_GRANULARITY 3	//# of ms between checking our socket/queues

#define TCPN_DEBUG				0
#define TCPN_DEBUG_Console		0
#define TCPN_DEBUG_Memory		0
#define TCPN_LOG_RAW_DATA_OUT	0		//1 = info, 2 = length limited dump, 3 = full dump
#define TCPN_LOG_RAW_DATA_IN	0		//1 = info, 2 = length limited dump, 3 = full dump

#ifdef DUAL_SERVER
#include "../world/LoginServer.h"
#endif

//client version
TCPConnection::TCPConnection()
: ConnectionType(Outgoing),
  connection_socket(0),
  id(0),
  rIP(0),
  rPort(0)
{
	pState = TCPS_Ready;
	pFree = false;
	pEcho = false;
	recvbuf = NULL;
	sendbuf = NULL;
	pRunLoop = false;
	charAsyncConnect = 0;
	pAsyncConnect = false;
	m_previousLineEnd = false;
#if TCPN_DEBUG_Memory >= 7
	cout << "Constructor #2 on outgoing TCP# " << GetID() << endl;
#endif
}

//server version
TCPConnection::TCPConnection(int32 ID, SOCKET in_socket, int32 irIP, int16 irPort)
: ConnectionType(Incomming),
  connection_socket(in_socket),
  id(ID),
  rIP(irIP),
  rPort(irPort)
{
	pState = TCPS_Connected;
	pFree = false;
	pEcho = false;
	recvbuf = NULL;
	sendbuf = NULL;
	pRunLoop = false;
	charAsyncConnect = 0;
	pAsyncConnect = false;
	m_previousLineEnd = false;
#if TCPN_DEBUG_Memory >= 7
	cout << "Constructor #2 on incoming TCP# " << GetID() << endl;
#endif
}

TCPConnection::~TCPConnection() {
	FinishDisconnect();
	ClearBuffers();
	if (ConnectionType == Outgoing) {
		MRunLoop.lock();
		pRunLoop = false;
		MRunLoop.unlock();
		MLoopRunning.lock();
		MLoopRunning.unlock();
#if TCPN_DEBUG_Memory >= 6
		cout << "Deconstructor on outgoing TCP# " << GetID() << endl;
#endif
	}
#if TCPN_DEBUG_Memory >= 5
	else {
		cout << "Deconstructor on incomming TCP# " << GetID() << endl;
	}
#endif
	safe_delete_array(recvbuf);
	safe_delete_array(sendbuf);
	safe_delete_array(charAsyncConnect);
}

void TCPConnection::SetState(State_t in_state) {
	MState.lock();
	pState = in_state;
	MState.unlock();
}

TCPConnection::State_t TCPConnection::GetState() const {
	State_t ret;
	MState.lock();
	ret = pState;
	MState.unlock();
	return ret;
}

bool TCPConnection::GetSockName(char *host, uint16 *port)
{
	bool result=false;
	LockMutex lock(&MState);
	if (!Connected())
		return false;

	struct sockaddr_in local;

#ifdef WIN32
	int addrlen;
#else
#ifdef FREEBSD
	socklen_t addrlen;
#else
	size_t addrlen;
#endif
#endif
	addrlen=sizeof(struct sockaddr_in);
#ifdef WIN32
	if (!getsockname(connection_socket,(struct sockaddr *)&local,&addrlen)) {
#else
	if (!getsockname(connection_socket,(struct sockaddr *)&local,(socklen_t *)&addrlen)) {
#endif
		unsigned long ip=local.sin_addr.s_addr;
		sprintf(host,"%d.%d.%d.%d",
			*(unsigned char *)&ip,
				*((unsigned char *)&ip+1),
				*((unsigned char *)&ip+2),
				*((unsigned char *)&ip+3));
		*port=ntohs(local.sin_port);

		result=true;
	}

	return result;
}

void TCPConnection::Free() {
	if (ConnectionType == Outgoing) {
		ThrowError("TCPConnection::Free() called on an Outgoing connection");
	}
#if TCPN_DEBUG_Memory >= 5
	cout << "Free on TCP# " << GetID() << endl;
#endif
	Disconnect();
	pFree = true;
}

bool TCPConnection::Send(const uchar* data, sint32 size) {
	if (!Connected())
		return false;
	if (!size)
		return true;
	ServerSendQueuePushEnd(data, size);
	return true;
}

void TCPConnection::ServerSendQueuePushEnd(const uchar* data, sint32 size) {
	MSendQueue.lock();
	if (sendbuf == NULL) {
		sendbuf = new uchar[size];
		sendbuf_size = size;
		sendbuf_used = 0;
	}
	else if (size > (sendbuf_size - sendbuf_used)) {
		sendbuf_size += size + 1024;
		uchar* tmp = new uchar[sendbuf_size];
		memcpy(tmp, sendbuf, sendbuf_used);
		safe_delete_array(sendbuf);
		sendbuf = tmp;
	}
	memcpy(&sendbuf[sendbuf_used], data, size);
	sendbuf_used += size;
	MSendQueue.unlock();
}

void TCPConnection::ServerSendQueuePushEnd(uchar** data, sint32 size) {
	MSendQueue.lock();
	if (sendbuf == 0) {
		sendbuf = *data;
		sendbuf_size = size;
		sendbuf_used = size;
		MSendQueue.unlock();
		*data = 0;
		return;
	}
	if (size > (sendbuf_size - sendbuf_used)) {
		sendbuf_size += size;
		uchar* tmp = new uchar[sendbuf_size];
		memcpy(tmp, sendbuf, sendbuf_used);
		safe_delete_array(sendbuf);
		sendbuf = tmp;
	}
	memcpy(&sendbuf[sendbuf_used], *data, size);
	sendbuf_used += size;
	MSendQueue.unlock();
	safe_delete_array(*data);
}

void TCPConnection::ServerSendQueuePushFront(uchar* data, sint32 size) {
	MSendQueue.lock();
	if (sendbuf == 0) {
		sendbuf = new uchar[size];
		sendbuf_size = size;
		sendbuf_used = 0;
	}
	else if (size > (sendbuf_size - sendbuf_used)) {
		sendbuf_size += size;
		uchar* tmp = new uchar[sendbuf_size];
		memcpy(&tmp[size], sendbuf, sendbuf_used);
		safe_delete_array(sendbuf);
		sendbuf = tmp;
	}
	memcpy(sendbuf, data, size);
	sendbuf_used += size;
	MSendQueue.unlock();
}

bool TCPConnection::ServerSendQueuePop(uchar** data, sint32* size) {
	bool ret;
	if (!MSendQueue.trylock())
		return false;
	if (sendbuf) {
		*data = sendbuf;
		*size = sendbuf_used;
		sendbuf = 0;
		ret = true;
	}
	else {
		ret = false;
	}
	MSendQueue.unlock();
	return ret;
}

bool TCPConnection::ServerSendQueuePopForce(uchar** data, sint32* size) {
	bool ret;
	MSendQueue.lock();
	if (sendbuf) {
		*data = sendbuf;
		*size = sendbuf_used;
		sendbuf = 0;
		ret = true;
	}
	else {
		ret = false;
	}
	MSendQueue.unlock();
	return ret;
}

char* TCPConnection::PopLine() {
	char* ret;
	if (!MLineOutQueue.trylock())
		return 0;
	ret = (char*) LineOutQueue.pop();
	MLineOutQueue.unlock();
	return ret;
}

bool TCPConnection::LineOutQueuePush(char* line) {
	MLineOutQueue.lock();
	LineOutQueue.push(line);
	MLineOutQueue.unlock();
	return(false);
}


void TCPConnection::FinishDisconnect() {
	MState.lock();
	if (connection_socket != INVALID_SOCKET && connection_socket != 0) {
		if (pState == TCPS_Connected || pState == TCPS_Disconnecting || pState == TCPS_Disconnected) {
			bool sent_something = false;
			SendData(sent_something);
		}
		pState = TCPS_Closing;
		shutdown(connection_socket, 0x01);
		shutdown(connection_socket, 0x00);
#ifdef WIN32
		closesocket(connection_socket);
#else
		close(connection_socket);
#endif
		connection_socket = 0;
		rIP = 0;
		rPort = 0;
		ClearBuffers();
	}
	pState = TCPS_Disconnected;
	MState.unlock();
}

void TCPConnection::Disconnect() {
	MState.lock();
	if(pState == TCPS_Connected || pState == TCPS_Connecting) {
		pState = TCPS_Disconnecting;
	}
	MState.unlock();
}

bool TCPConnection::GetAsyncConnect() {
	bool ret;
	MAsyncConnect.lock();
	ret = pAsyncConnect;
	MAsyncConnect.unlock();
	return ret;
}

bool TCPConnection::SetAsyncConnect(bool iValue) {
	bool ret;
	MAsyncConnect.lock();
	ret = pAsyncConnect;
	pAsyncConnect = iValue;
	MAsyncConnect.unlock();
	return ret;
}

bool TCPConnection::ConnectReady() const {
	State_t s = GetState();
	if (s != TCPS_Ready && s != TCPS_Disconnected)
		return(false);
	return(ConnectionType == Outgoing);
}

void TCPConnection::AsyncConnect(const char* irAddress, int16 irPort) {
	safe_delete_array(charAsyncConnect);
	charAsyncConnect = new char[strlen(irAddress) + 1];
	strcpy(charAsyncConnect, irAddress);
	AsyncConnect((int32) 0, irPort);
}

void TCPConnection::AsyncConnect(int32 irIP, int16 irPort) {
	if (ConnectionType != Outgoing) {
		// If this code runs, we got serious problems
		// Crash and burn.
		ThrowError("TCPConnection::AsyncConnect() call on a Incomming connection object!");
		return;
	}
	if(!ConnectReady()) {
#if TCPN_DEBUG > 0
		printf("Trying to do async connect in invalid state %s\n", GetState());
#endif
		return;
	}
	MAsyncConnect.lock();
	if (pAsyncConnect) {
		MAsyncConnect.unlock();
#if TCPN_DEBUG > 0
		printf("Trying to do async connect when already doing one.\n");
#endif
		return;
	}
#if TCPN_DEBUG > 0
		printf("Start async connect.\n");
#endif
	pAsyncConnect = true;
	if(irIP != 0)
		safe_delete_array(charAsyncConnect);
	rIP = irIP;
	rPort = irPort;
	MAsyncConnect.unlock();
	if (!pRunLoop) {
		pRunLoop = true;
#ifdef WIN32
		_beginthread(TCPConnectionLoop, 0, this);
#else
		pthread_t thread;
		pthread_create(&thread, NULL, TCPConnectionLoop, this);
#endif
	}
	return;
}

bool TCPConnection::Connect(const char* irAddress, int16 irPort, char* errbuf) {
	if (errbuf)
		errbuf[0] = 0;
	int32 tmpIP = ResolveIP(irAddress);
	if (!tmpIP) {
		if (errbuf) {
#ifdef WIN32
			snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::Connect(): Couldnt resolve hostname. Error: %i", WSAGetLastError());
#else
			snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::Connect(): Couldnt resolve hostname. Error #%i: %s", errno, strerror(errno));
#endif
		}
		return false;
	}
	return ConnectIP(tmpIP, irPort, errbuf);
}

bool TCPConnection::ConnectIP(int32 in_ip, int16 in_port, char* errbuf) {
	if (errbuf)
		errbuf[0] = 0;
	if (ConnectionType != Outgoing) {
		// If this code runs, we got serious problems
		// Crash and burn.
		ThrowError("TCPConnection::Connect() call on a Incomming connection object!");
		return false;
	}
	MState.lock();
	if (ConnectReady()) {
		pState = TCPS_Connecting;
	} else {
		MState.unlock();
		SetAsyncConnect(false);
		return false;
	}
	MState.unlock();
	if (!pRunLoop) {
		pRunLoop = true;
#ifdef WIN32
		_beginthread(TCPConnectionLoop, 0, this);
#else
		pthread_t thread;
		pthread_create(&thread, NULL, TCPConnectionLoop, this);
#endif
	}

	connection_socket = INVALID_SOCKET;
    struct sockaddr_in	server_sin;
//    struct in_addr	in;

	if ((connection_socket = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET || connection_socket == 0) {
#ifdef WIN32
		if (errbuf)
			snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::Connect(): Allocating socket failed. Error: %i", WSAGetLastError());
#else
		if (errbuf)
			snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::Connect(): Allocating socket failed. Error: %s", strerror(errno));
#endif
		SetState(TCPS_Ready);
		SetAsyncConnect(false);
		return false;
	}
	server_sin.sin_family = AF_INET;
	server_sin.sin_addr.s_addr = in_ip;
	server_sin.sin_port = htons(in_port);

	// Establish a connection to the server socket.
#ifdef WIN32
	if (connect(connection_socket, (PSOCKADDR) &server_sin, sizeof (server_sin)) == SOCKET_ERROR) {
		if (errbuf)
			snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::Connect(): connect() failed. Error: %i", WSAGetLastError());
		closesocket(connection_socket);
		connection_socket = 0;
		SetState(TCPS_Ready);
		SetAsyncConnect(false);
		return false;
	}
#else
	if (connect(connection_socket, (struct sockaddr *) &server_sin, sizeof (server_sin)) == SOCKET_ERROR) {
		if (errbuf)
			snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::Connect(): connect() failed. Error: %s", strerror(errno));
		close(connection_socket);
		connection_socket = 0;
		SetState(TCPS_Ready);
		SetAsyncConnect(false);
		return false;
	}
#endif
	int bufsize = 64 * 1024; // 64kbyte recieve buffer, up from default of 8k
	setsockopt(connection_socket, SOL_SOCKET, SO_RCVBUF, (char*) &bufsize, sizeof(bufsize));
#ifdef WIN32
	unsigned long nonblocking = 1;
	ioctlsocket(connection_socket, FIONBIO, &nonblocking);
#else
	fcntl(connection_socket, F_SETFL, O_NONBLOCK);
#endif

	SetEcho(false);
	ClearBuffers();
	
	rIP = in_ip;
	rPort = in_port;
	SetState(TCPS_Connected);
	SetAsyncConnect(false);
	return true;
}

void TCPConnection::ClearBuffers() {
	LockMutex lock1(&MSendQueue);
	LockMutex lock3(&MRunLoop);
	LockMutex lock4(&MState);
	safe_delete_array(recvbuf);
	safe_delete_array(sendbuf);
	
	char* line = 0;
	while ((line = LineOutQueue.pop()))
		safe_delete_array(line);
}

bool TCPConnection::CheckNetActive() {
	MState.lock();
	if (pState == TCPS_Connected || pState == TCPS_Disconnecting) {
		MState.unlock();
		return true;
	}
	MState.unlock();
	return false;
}

/* This is always called from an IO thread. Either the server socket's thread, or a 
 * special thread we create when we make an outbound connection. */
bool TCPConnection::Process() {
	char errbuf[TCPConnection_ErrorBufferSize];
	switch(GetState()) {
	case TCPS_Ready:
	case TCPS_Connecting:
		if (ConnectionType == Outgoing) {
			if (GetAsyncConnect()) {
				if (charAsyncConnect)
					rIP = ResolveIP(charAsyncConnect);
				ConnectIP(rIP, rPort);
			}
		}
		return(true);
	
	case TCPS_Connected:
		// only receive data in the connected state, no others...
		if (!RecvData(errbuf)) {
		    struct in_addr	in;
			in.s_addr = GetrIP();
			//cout << inet_ntoa(in) << ":" << GetrPort() << ": " << errbuf << endl;
			return false;
		}
		/* we break to do the send */
		break;
	
	case TCPS_Disconnecting: {
		//waiting for any sending data to go out...
		MSendQueue.lock();
		if(sendbuf) {
			if(sendbuf_used > 0) {
				//something left to send, keep processing...
				MSendQueue.unlock();
				break;
			}
			//else, send buffer is empty.
			safe_delete_array(sendbuf);
		} //else, no send buffer, we are done.
		MSendQueue.unlock();
	}
		/* Fallthrough */
	
	case TCPS_Disconnected:
		FinishDisconnect();
		MRunLoop.lock();
		pRunLoop = false;
		MRunLoop.unlock();
//		SetState(TCPS_Ready);	//reset the state in case they want to use it again...
		return(false);
	
	case TCPS_Closing:
		//I dont understand this state...
	
	case TCPS_Error:
		MRunLoop.lock();
		pRunLoop = false;
		MRunLoop.unlock();
		return(false);
	}
	
	/* we get here in connected or disconnecting with more data to send */
	
	bool sent_something = false;
	if (!SendData(sent_something, errbuf)) {
	    struct in_addr	in;
		in.s_addr = GetrIP();
		cout << inet_ntoa(in) << ":" << GetrPort() << ": " << errbuf << endl;
		return false;
	}
	
	return true;
}

bool TCPConnection::RecvData(char* errbuf) {
	if (errbuf)
		errbuf[0] = 0;
	if (!Connected()) {
		return false;
	}

	int	status = 0;
	if (recvbuf == 0) {
		recvbuf = new uchar[5120];
		recvbuf_size = 5120;
		recvbuf_used = 0;
		recvbuf_echo = 0;
	}
	else if ((recvbuf_size - recvbuf_used) < 2048) {
		uchar* tmpbuf = new uchar[recvbuf_size + 5120];
		memcpy(tmpbuf, recvbuf, recvbuf_used);
		recvbuf_size += 5120;
		safe_delete_array(recvbuf);
		recvbuf = tmpbuf;
		if (recvbuf_size >= MaxTCPReceiveBuffferSize) {
			if (errbuf)
				snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::RecvData(): recvbuf_size >= MaxTCPReceiveBuffferSize");
			return false;
		}
	}

    status = recv(connection_socket, (char *) &recvbuf[recvbuf_used], (recvbuf_size - recvbuf_used), 0);

    if (status >= 1) {
#if TCPN_LOG_RAW_DATA_IN >= 1
		struct in_addr	in;
		in.s_addr = GetrIP();
		CoutTimestamp(true);
		cout << ": Read " << status << " bytes from network. (recvbuf_used = " << recvbuf_used << ") " << inet_ntoa(in) << ":" << GetrPort();
		cout << endl;
	#if TCPN_LOG_RAW_DATA_IN == 2
		sint32 tmp = status;
		if (tmp > 32)
			tmp = 32;
		DumpPacket(&recvbuf[recvbuf_used], status);
	#elif TCPN_LOG_RAW_DATA_IN >= 3
		DumpPacket(&recvbuf[recvbuf_used], status);
	#endif
#endif
		recvbuf_used += status;
		if (!ProcessReceivedData(errbuf))
			return false;
    }
	else if (status == SOCKET_ERROR) {
#ifdef WIN32
		if (!(WSAGetLastError() == WSAEWOULDBLOCK)) {
			if (errbuf)
				snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::RecvData(): Error: %i", WSAGetLastError());
			return false;
		}
#else
		if (!(errno == EWOULDBLOCK)) {
			if (errbuf)
				snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::RecvData(): Error: %s", strerror(errno));
			return false;
		}
#endif
	} else if (status == 0) {
		snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::RecvData(): Connection closed");
		return false;
	}

	return true;
}


bool TCPConnection::GetEcho() {
	bool ret;
	ret = pEcho;
	return ret;
}

void TCPConnection::SetEcho(bool iValue) {
	pEcho = iValue;
}

bool TCPConnection::ProcessReceivedData(char* errbuf) {
	if (errbuf)
		errbuf[0] = 0;
	if (!recvbuf)
		return true;
#if TCPN_DEBUG_Console >= 4
	if (recvbuf_used) {
		cout << "Starting Processing: recvbuf=" << recvbuf_used << endl;
		DumpPacket(recvbuf, recvbuf_used);
	}
#endif
	for (int i=0; i < recvbuf_used; i++) {
		if (GetEcho() && i >= recvbuf_echo) {
			Send(&recvbuf[i], 1);
			recvbuf_echo = i + 1;
		}
		switch(recvbuf[i]) {
		case 0: { // 0 is the code for clear buffer
				if (i==0) {
					recvbuf_used--;
					recvbuf_echo--;
					memmove(recvbuf, &recvbuf[1], recvbuf_used);
					i = -1;
				} else {
					if (i == recvbuf_used) {
						safe_delete_array(recvbuf);
						i = -1;
					}
					else {
						uchar* tmpdel = recvbuf;
						recvbuf = new uchar[recvbuf_size];
						memcpy(recvbuf, &tmpdel[i+1], recvbuf_used-i);
						recvbuf_used -= i + 1;
						recvbuf_echo -= i + 1;
						safe_delete_array(tmpdel);
						i = -1;
					}
				}
#if TCPN_DEBUG_Console >= 5
				cout << "Removed 0x00" << endl;
				if (recvbuf_used) {
					cout << "recvbuf left: " << recvbuf_used << endl;
					DumpPacket(recvbuf, recvbuf_used);
				}
				else
					cout << "recbuf left: None" << endl;
#endif
				m_previousLineEnd = false;
				break;
			}
			case 10:
			case 13: // newline marker
			{
				char *line = NULL;
				if (i==0) { // empty line
					if(!m_previousLineEnd) {
						//char right before this was NOT a CR, report the empty line.
						line = new char[1];
						line[0] = '\0';
						m_previousLineEnd = true;
					} else {
						m_previousLineEnd = false;
					}
					recvbuf_used--;
					recvbuf_echo--;
					memcpy(recvbuf, &recvbuf[1], recvbuf_used);
					i = -1;
				} else {
					line = new char[i+1];
					memset(line, 0, i+1);
					memcpy(line, recvbuf, i);
#if TCPN_DEBUG_Console >= 3
					cout << "Line Out: " << endl;
					DumpPacket((uchar*) line, i);
#endif
					//line[i] = 0;
					uchar* tmpdel = recvbuf;
					recvbuf = new uchar[recvbuf_size];
					recvbuf_used -= i+1;
					recvbuf_echo -= i+1;
					memcpy(recvbuf, &tmpdel[i+1], recvbuf_used);
#if TCPN_DEBUG_Console >= 5
					cout << "i+1=" << i+1 << endl;
					if (recvbuf_used) {
						cout << "recvbuf left: " << recvbuf_used << endl;
						DumpPacket(recvbuf, recvbuf_used);
					}
					else
						cout << "recbuf left: None" << endl;
#endif
					safe_delete_array(tmpdel);
					i = -1;
					m_previousLineEnd = true;
				}
				
				
				if(line != NULL) {
					bool finish_proc = false;
					finish_proc = LineOutQueuePush(line);
					if(finish_proc)
						return(true);	//break early as requested by LineOutQueuePush
				}
				
				break;
			}
			case 8: // backspace
			{
				if (i==0) { // nothin to backspace
					recvbuf_used--;
					recvbuf_echo--;
					memmove(recvbuf, &recvbuf[1], recvbuf_used);
					i = -1;
				} else {
					uchar* tmpdel = recvbuf;
					recvbuf = new uchar[recvbuf_size];
					memcpy(recvbuf, tmpdel, i-1);
					memcpy(&recvbuf[i-1], &tmpdel[i+1], recvbuf_used-i);
					recvbuf_used -= 2;
					recvbuf_echo -= 2;
					safe_delete_array(tmpdel);
					i -= 2;
				}
				break;
				m_previousLineEnd = false;
			}
			default:
				m_previousLineEnd = false;
		}
	}
	if (recvbuf_used < 0)
		safe_delete_array(recvbuf);
	return true;
}

bool TCPConnection::SendData(bool &sent_something, char* errbuf) {
	if (errbuf)
		errbuf[0] = 0;
	/************ Get first send packet on queue and send it! ************/
	uchar* data = 0;
	sint32 size = 0;
	int status = 0;
	if (ServerSendQueuePop(&data, &size)) {
#ifdef WIN32
		status = send(connection_socket, (const char *) data, size, 0);
#else
		status = send(connection_socket, data, size, MSG_NOSIGNAL);
		if(errno==EPIPE) status = SOCKET_ERROR;
#endif
		if (status >= 1) {
#if TCPN_LOG_RAW_DATA_OUT >= 1
			struct in_addr	in;
			in.s_addr = GetrIP();
			CoutTimestamp(true);
			cout << ": Wrote " << status << " bytes to network. " << inet_ntoa(in) << ":" << GetrPort();
			cout << endl;
	#if TCPN_LOG_RAW_DATA_OUT == 2
			sint32 tmp = status;
			if (tmp > 32)
				tmp = 32;
			DumpPacket(data, status);
	#elif TCPN_LOG_RAW_DATA_OUT >= 3
			DumpPacket(data, status);
	#endif
#endif
			sent_something = true;
			if (status < (signed)size) {
#if TCPN_LOG_RAW_DATA_OUT >= 1
				struct in_addr	in;
				in.s_addr = GetrIP();
				CoutTimestamp(true);
				cout << ": Pushed " << (size - status) << " bytes back onto the send queue. " << inet_ntoa(in) << ":" << GetrPort();
				cout << endl;
#endif
				// If there's network congestion, the number of bytes sent can be less than
				// what we tried to give it... Push the extra back on the queue for later
				ServerSendQueuePushFront(&data[status], size - status);
			}
			else if (status > (signed)size) {
				ThrowError("TCPConnection::SendData(): WTF! status > size");
				return false;
			}
			// else if (status == size) {}
		}
		else {
			ServerSendQueuePushFront(data, size);
		}

		safe_delete_array(data);
		if (status == SOCKET_ERROR) {
#ifdef WIN32
			if (WSAGetLastError() != WSAEWOULDBLOCK)
#else
			if (errno != EWOULDBLOCK)
#endif
			{
				if (errbuf) {
#ifdef WIN32
					snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::SendData(): send(): Errorcode: %i", WSAGetLastError());
#else
					snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::SendData(): send(): Errorcode: %s", strerror(errno));
#endif
				}
				
				//if we get an error while disconnecting, just jump to disconnected
				MState.lock();
				if(pState == TCPS_Disconnecting)
					pState = TCPS_Disconnected;
				MState.unlock();
				
				return false;
			}
		}
	}
	return true;
}

ThreadReturnType TCPConnection::TCPConnectionLoop(void* tmp) {
#ifdef WIN32
	SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
#endif
	if (tmp == 0) {
		ThrowError("TCPConnectionLoop(): tmp = 0!");
		THREAD_RETURN(NULL);
	}
	TCPConnection* tcpc = (TCPConnection*) tmp;
#ifndef WIN32
	_log(COMMON__THREADS, "Starting TCPConnectionLoop with thread ID %d", pthread_self());
#endif
	tcpc->MLoopRunning.lock();
	while (tcpc->RunLoop()) {
		Sleep(LOOP_GRANULARITY);
		if (!tcpc->ConnectReady()) {
			_CP(TCPConnectionLoop);
			if (!tcpc->Process()) {
				//the processing loop has detecting an error.. 
				//we want to drop the link immediately, so we clear buffers too.
				tcpc->ClearBuffers();
				tcpc->Disconnect();
			}
#ifdef DUAL_SERVER
			Sleep(100);
#else
			Sleep(1);
#endif
		}
		else if (tcpc->GetAsyncConnect()) {
			_CP(TCPConnectionLoop);
			if (tcpc->charAsyncConnect)
				tcpc->Connect(tcpc->charAsyncConnect, tcpc->GetrPort());
			else
				tcpc->ConnectIP(tcpc->GetrIP(), tcpc->GetrPort());
			tcpc->SetAsyncConnect(false);
		}
		else
			Sleep(10);	//nothing to do.
	}
	tcpc->MLoopRunning.unlock();
	
#ifndef WIN32
#ifdef DUAL_SERVER
	_log(COMMON__THREADS, "Ending TCPConnectionLoop with thread ID %d, Did you loose a server connection?", pthread_self()); //Angelox
#else
	_log(COMMON__THREADS, "Ending TCPConnectionLoop with thread ID %d", pthread_self());
#endif
#endif
	
	THREAD_RETURN(NULL);

#ifdef DUAL_SERVER
	_log(WORLD__CONSOLE,"Login Server Reconnect Attempt...");
	InitLoginServer();
/*	#ifdef WIN32
		_beginthread(AutoInitLoginServer, 0, NULL);
	#else
		pthread_t thread;
		pthread_create(&thread, NULL, &AutoInitLoginServer, NULL);
	#endif
	RunLoops = true;
	_log(WORLD__CONSOLE,"Login Server Reconnect Attempt..."); */
#endif
}

bool TCPConnection::RunLoop() {
	bool ret;
	MRunLoop.lock();
	ret = pRunLoop;
	MRunLoop.unlock();
	return ret;
}
database.cpp
Code:
#include "../common/debug.h"
#include <iostream>
using namespace std;
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errmsg.h>
#include <mysqld_error.h>
#include <limits.h>
#include <ctype.h>
#include <assert.h>
#include <map>

// Disgrace: for windows compile
#ifdef WIN32
#include <windows.h>
#define snprintf	_snprintf
#define strncasecmp	_strnicmp
#define strcasecmp	_stricmp
#else
#include "unix.h"
#include <netinet/in.h>
#include <sys/time.h>
#endif

#ifdef EQBOTS
#include "../zone/botDatabase.h"
#endif //EQBOTS

#include "database.h"
#include "eq_packet_structs.h"
#include "guilds.h"
#include "MiscFunctions.h"
#include "extprofile.h"
/*#include "../common/classes.h"
#include "../common/races.h"
#include "../common/files.h"
#include "../common/EQEMuError.h"
#include "../common/packet_dump.h"
*/
extern Client client;

/*
This is the amount of time in seconds the client has to enter the zone
server after the world server, or inbetween zones when that is finished
*/

/*
Establish a connection to a mysql database with the supplied parameters

  Added a very simple .ini file parser - Bounce

	Modify to use for win32 & linux - misanthropicfiend
*/
Database::Database ()
{
	DBInitVars();
}

/*
Establish a connection to a mysql database with the supplied parameters
*/

Database::Database(const char* host, const char* user, const char* passwd, const char* database, int32 port)
{
	DBInitVars();
	Connect(host, user, passwd, database, port);
}

bool Database::Connect(const char* host, const char* user, const char* passwd, const char* database, int32 port)
{
	int32 errnum= 0;
	char errbuf[MYSQL_ERRMSG_SIZE];
	if (!Open(host, user, passwd, database, port, &errnum, errbuf))
	{
		LogFile->write(EQEMuLog::Error, "Failed to connect to database: Error: %s", errbuf);
		HandleMysqlError(errnum);

		return false;
	}
	else
	{
		LogFile->write(EQEMuLog::Status, "Using database '%s' at %s:%d",database,host,port);
		return true;
	}
}

void Database::DBInitVars() {

	max_zonename = 0;
	zonename_array = 0;
	varcache_array = 0;
	varcache_max = 0;
	varcache_lastupdate = 0;
}



void Database::HandleMysqlError(int32 errnum) {
/*	switch(errnum) {
		case 0:
			break;
		case 1045: // Access Denied
		case 2001: {
			AddEQEMuError(EQEMuError_Mysql_1405, true);
			break;
		}
		case 2003: { // Unable to connect
			AddEQEMuError(EQEMuError_Mysql_2003, true);
			break;
		}
		case 2005: { // Unable to connect
			AddEQEMuError(EQEMuError_Mysql_2005, true);
			break;
		}
		case 2007: { // Unable to connect
			AddEQEMuError(EQEMuError_Mysql_2007, true);
			break;
		}
	}*/
}

/*

Close the connection to the database
*/
Database::~Database()
{
	unsigned int x;
	if (zonename_array) {
		for (x=0; x<=max_zonename; x++) {
			if (zonename_array[x])
				safe_delete_array(zonename_array[x]);
		}
		safe_delete_array(zonename_array);
	}
	if (varcache_array) {
		for (x=0; x<varcache_max; x++) {
			safe_delete_array(varcache_array[x]);
		}
		safe_delete_array(varcache_array);
	}
}


/*
Check if there is an account with name "name" and password "password"
Return the account id or zero if no account matches.
Zero will also be returned if there is a database error.
*/
int32 Database::CheckLogin(const char* name, const char* password, sint16* oStatus) {
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
    MYSQL_RES *result;
    MYSQL_ROW row;

	if(strlen(name) >= 50 || strlen(password) >= 50)
		return(0);

	char tmpUN[100];
	char tmpPW[100];
	DoEscapeString(tmpUN, name, strlen(name));
	DoEscapeString(tmpPW, password, strlen(password));

	if (RunQuery(query, MakeAnyLenString(&query,
		"SELECT id, status FROM account WHERE name='%s' AND password is not null "
		"and length(password) > 0 and (password='%s' or password=MD5('%s'))",
		tmpUN, tmpPW, tmpPW), errbuf, &result)) {
		safe_delete_array(query);
		if (mysql_num_rows(result) == 1)
		{
			row = mysql_fetch_row(result);
			int32 id = atoi(row[0]);
			if (oStatus)
				*oStatus = atoi(row[1]);
			mysql_free_result(result);
			return id;
		}
		else
		{
			mysql_free_result(result);
			return 0;
		}
		mysql_free_result(result);
	}
	else
	{
		cerr << "Error in CheckLogin query '" << query << "' " << errbuf << endl;
		safe_delete_array(query);
		return false;
	}

	return 0;
}


//Lieka:  Get Banned IP Address List - Only return false if the incoming connection's IP address is not present in the banned_ips table.
bool Database::CheckBannedIPs(const char* loginIP)
{
 	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
    MYSQL_RES *result;
 	//cout << "Checking against Banned IPs table."<< endl; //Lieka:  Debugging
 	if (RunQuery(query, MakeAnyLenString(&query, "SELECT ip_address FROM Banned_IPs WHERE ip_address='%s'", loginIP), errbuf, &result)) {
 		safe_delete_array(query);
 		if (mysql_num_rows(result) != 0)
 		{
 			//cout << loginIP << " was present in the banned IPs table" << endl; //Lieka:  Debugging
 			mysql_free_result(result);
 			return true;
 		}
 		else
 		{
 			//cout << loginIP << " was not present in the banned IPs table." << endl; //Lieka:  Debugging
 			mysql_free_result(result);
 			return false;
 		}
 		mysql_free_result(result);
 	}
 	else
 	{
 		cerr << "Error in CheckBannedIPs query '" << query << "' " << errbuf << endl;
 		safe_delete_array(query);
 		return true;
 	}
 	return true;
}

bool Database::AddBannedIP(char* bannedIP, const char* notes)
{
 	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;

 	if (!RunQuery(query, MakeAnyLenString(&query, "INSERT into Banned_IPs SET ip_address='%s', notes='%s'", bannedIP, notes), errbuf)) {
 		cerr << "Error in ReserveName query '" << query << "' " << errbuf << endl;
 		safe_delete_array(query);
 		return false;
 	}
 	safe_delete_array(query);
 	return true;
}
 //End Lieka Edit
 
 bool Database::CheckGMIPs(const char* ip_address, int32 account_id) {
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	if (RunQuery(query, MakeAnyLenString(&query, "SELECT * FROM `gm_ips` WHERE `ip_address` = '%s' AND `account_id` = %i", ip_address, account_id), errbuf, &result)) {
		safe_delete_array(query);
		if (mysql_num_rows(result) == 1) {
			mysql_free_result(result);
			return true;
		} else {
			mysql_free_result(result);
			return false;
		}
		mysql_free_result(result);

	} else {
		safe_delete_array(query);
		return false;
	}
	
	return false;
}

bool Database::AddGMIP(char* ip_address, char* name) {
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;

	if (!RunQuery(query, MakeAnyLenString(&query, "INSERT into `gm_ips` SET `ip_address` = '%s', `name` = '%s'", ip_address, name), errbuf)) {
		safe_delete_array(query);
		return false;
	}
	safe_delete_array(query);
	return true;
}

void Database::LoginIP(int32 AccountID, const char* LoginIP)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;

	if (!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO account_ip SET accid=%i, ip='%s' ON DUPLICATE KEY UPDATE count=count+1, lastused=now()", AccountID, LoginIP), errbuf)) {
 		cerr << "Error in Log IP query '" << query << "' " << errbuf << endl;
 	}
 	safe_delete_array(query);
}

sint16 Database::CheckStatus(int32 account_id)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
    MYSQL_RES *result;
    MYSQL_ROW row;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT status FROM account WHERE id='%i'", account_id), errbuf, &result)) {
		safe_delete_array(query);
		if (mysql_num_rows(result) == 1)
		{
			row = mysql_fetch_row(result);
			sint16 status = atoi(row[0]);

			mysql_free_result(result);
			return status;
		}
		else
		{
			mysql_free_result(result);
			return 0;
		}
		mysql_free_result(result);
	}
	else
	{
		cerr << "Error in CheckStatus query '" << query << "' " << errbuf << endl;
		safe_delete_array(query);
		return false;
	}

	return 0;
}

#ifdef DUAL_SERVER
int32 Database::CreateAccount(const char* name, const char* password, sint16 status, int32 lsaccount_id, int32 lsaccount_id2) {
#else
int32 Database::CreateAccount(const char* name, const char* password, sint16 status, int32 lsaccount_id) {
#endif
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	int32 querylen;
	int32 last_insert_id;
	MYSQL_RES *result;
// if (paccountid == 0 && LSID()>0) {

#ifdef DUAL_SERVER
    RunQuery(query, MakeAnyLenString(&query, "SELECT id, status, lsaccount_id FROM account WHERE name='%s'", name), errbuf, &result);
    if (mysql_num_rows(result) == 1) {
      lsaccount_id2 = lsaccount_id;
      safe_delete_array(query); 
      if (lsaccount_id > 4999999){
	(!RunQuery(query, MakeAnyLenString(&query, "UPDATE account SET lsaccount_id=%i WHERE name='%s'AND lsaccount_id IS NULL;", lsaccount_id, name), errbuf, 0));
	safe_delete_array(query);
      }
      else if (lsaccount_id < 5000000){
	(!RunQuery(query, MakeAnyLenString(&query, "UPDATE account SET lsaccount_id2=%i WHERE name='%s'AND lsaccount_id2='0';", lsaccount_id2, name), errbuf, 0));
	safe_delete_array(query);
      }
      safe_delete_array(query);
    }
   safe_delete_array(query);

	    if ((password) && (lsaccount_id > 4999999))
#else
	    if (password)
#endif

		querylen = MakeAnyLenString(&query, "INSERT INTO account SET name='%s', password='%s', status=%i, lsaccount_id=%i;",name,password,status, lsaccount_id);
	
#ifdef DUAL_SERVER	
	    else if (lsaccount_id > 4999999)
		querylen = MakeAnyLenString(&query, "INSERT INTO account SET name='%s', status=%i, lsaccount_id=%i;",name, status, lsaccount_id);
#else
	    else
		querylen = MakeAnyLenString(&query, "INSERT INTO account SET name='%s', status=%i, lsaccount_id=%i;",name, status, lsaccount_id);
#endif

#ifdef DUAL_SERVER
  lsaccount_id2 = lsaccount_id;
  if ((password) && (lsaccount_id < 5000000))
		querylen = MakeAnyLenString(&query, "INSERT INTO account SET name='%s', password='%s', status=%i, lsaccount_id2=%i;",name,password,status, lsaccount_id2);
	else if (lsaccount_id < 5000000)
		querylen = MakeAnyLenString(&query, "INSERT INTO account SET name='%s', status=%i, lsaccount_id2=%i;",name, status, lsaccount_id2);
#endif //Dual Server

	cerr << "Account Attempting to be created:" << name << " " << (sint16) status << endl;
	if (!RunQuery(query, querylen, errbuf, 0, 0, &last_insert_id)) {
		cerr << "Error in CreateAccount query, possible second account added,try again- '" << query << "' " << errbuf << endl;
		safe_delete_array(query);
		return 0;
	}
	safe_delete_array(query);

	if (last_insert_id == 0) {
		cerr << "Error in CreateAccount query '" << query << "' " << errbuf << endl;
		return 0;
	}
	return last_insert_id;
}

bool Database::DeleteAccount(const char* name) {
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	int32 affected_rows = 0;

	cerr << "Account Attempting to be deleted:" << name << endl;
	if (RunQuery(query, MakeAnyLenString(&query, "DELETE FROM account WHERE name='%s';",name), errbuf, 0, &affected_rows)) {
		safe_delete_array(query);
		if (affected_rows == 1) {
			return true;
		}
	}
	else {

		cerr << "Error in DeleteAccount query '" << query << "' " << errbuf << endl;
		safe_delete_array(query);
	}

	return false;
}

bool Database::SetLocalPassword(int32 accid, const char* password) {
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;

	if (!RunQuery(query, MakeAnyLenString(&query, "UPDATE account SET password=MD5('%s') where id=%i;", password, accid), errbuf)) {
		cerr << "Error in SetLocalPassword query '" << query << "' " << errbuf << endl;
		safe_delete_array(query);
		return false;
	}

	safe_delete_array(query);
	return true;
}

bool Database::SetAccountStatus(const char* name, sint16 status) {
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	int32	affected_rows = 0;

	cout << "Account being GM Flagged:" << name << ", Level: " << (sint16) status << endl;
	if (!RunQuery(query, MakeAnyLenString(&query, "UPDATE account SET status=%i WHERE name='%s';", status, name), errbuf, 0, &affected_rows)) {
		safe_delete_array(query);
		return false;
	}
	safe_delete_array(query);

	if (affected_rows == 0) {
		cout << "Account: " << name << " does not exist, therefore it cannot be flagged\n";
		return false;
	}

	return true;
}


//---------------------------------
//End of adventure database code.--
//---------------------------------


bool Database::ReserveName(int32 account_id, char* name)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;

	if (!RunQuery(query, MakeAnyLenString(&query, "INSERT into character_ SET account_id=%i, name='%s', profile=NULL", account_id, name), errbuf)) {
		cerr << "Error in ReserveName query '" << query << "' " << errbuf << endl;
		safe_delete_array(query);
		return false;
	}
	safe_delete_array(query);
	return true;
}

/*
Delete the character with the name "name"
returns false on failure, true otherwise
*/
bool Database::DeleteCharacter(char *name)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query=0;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int charid, matches;
	int32 affected_rows;

	if(!name ||	!strlen(name))
	{
		printf("DeleteCharacter: request to delete without a name (empty char slot)\n");
		return false;
	}

// SCORPIOUS2K - get id from character_ before deleting record so we can clean up inventory and qglobal

#if DEBUG >= 5
	printf("DeleteCharacter: Attempting to delete '%s'\n", name);
#endif
	RunQuery(query, MakeAnyLenString(&query, "SELECT id from character_ WHERE name='%s'", name), errbuf, &result);
	if (query)
	{
		safe_delete_array(query);
		query = NULL;
	}
	matches = mysql_num_rows(result);
	if(matches == 1)
	{
		row = mysql_fetch_row(result);
		charid = atoi(row[0]);
#if DEBUG >= 5
		printf("DeleteCharacter: found '%s' with char id: %d\n", name, charid);
#endif
	}
	else
	{
		printf("DeleteCharacter: error: got %d rows matching '%s'\n", matches, name);
		if(result)
		{
			mysql_free_result(result);
			result = NULL;
		}
		return false;
	}

	if(result)
	{
		mysql_free_result(result);
		result = NULL;
	}



#if DEBUG >= 5
	printf("DeleteCharacter: deleting '%s' (id %d): ", name, charid);
	printf(" quest_globals");
#endif
	RunQuery(query, MakeAnyLenString(&query, "DELETE from quest_globals WHERE charid='%d'", charid), errbuf, NULL, &affected_rows);
	if(query)
	{
		safe_delete_array(query);
		query = NULL;
	}

#if DEBUG >= 5
	printf(" character_tasks");
#endif
	RunQuery(query, MakeAnyLenString(&query, "DELETE from character_tasks WHERE charid='%d'", charid), errbuf, NULL, &affected_rows);
	if(query)
	{
		safe_delete_array(query);
		query = NULL;
	}

#if DEBUG >= 5
	printf(" character_activities");
#endif
	RunQuery(query, MakeAnyLenString(&query, "DELETE from character_activities WHERE charid='%d'", charid), errbuf, NULL, &affected_rows);
	if(query)
	{
		safe_delete_array(query);
		query = NULL;
	}

#if DEBUG >= 5
	printf(" character_enabledtasks");
#endif
	RunQuery(query, MakeAnyLenString(&query, "DELETE from character_enabledtasks WHERE charid='%d'", charid), errbuf, NULL, &affected_rows);
	if(query)
	{
		safe_delete_array(query);
		query = NULL;
	}

#if DEBUG >= 5
	printf(" completed_tasks");
#endif
	RunQuery(query, MakeAnyLenString(&query, "DELETE from completed_tasks WHERE charid='%d'", charid), errbuf, NULL, &affected_rows);
	if(query)
	{
		safe_delete_array(query);
		query = NULL;
	}

#if DEBUG >= 5
	printf(" friends");
#endif
	RunQuery(query, MakeAnyLenString(&query, "DELETE from friends WHERE charid='%d'", charid), errbuf, NULL, &affected_rows);
	if(query)
	{
		safe_delete_array(query);
		query = NULL;
	}

#if DEBUG >= 5
	printf(" ptimers");
#endif
	RunQuery(query, MakeAnyLenString(&query, "DELETE from timers WHERE char_id='%d'", charid), errbuf, NULL, &affected_rows);
	if(query)
	{
		safe_delete_array(query);
		query = NULL;
	}

#if DEBUG >= 5
	printf(" inventory");
#endif
	RunQuery(query, MakeAnyLenString(&query, "DELETE from inventory WHERE charid='%d'", charid), errbuf, NULL, &affected_rows);
	if(query)
	{
		safe_delete_array(query);
		query = NULL;
	}

#if DEBUG >= 5
	printf(" guild_members");
#endif
	RunQuery(query, MakeAnyLenString(&query, "DELETE FROM guild_members WHERE char_id='%d'", charid), errbuf, NULL, &affected_rows);
	if(query)
	{
		safe_delete_array(query);
		query = NULL;
	}

#if DEBUG >= 5
	printf(" _character");
#endif
	RunQuery(query, MakeAnyLenString(&query, "DELETE from character_ WHERE id='%d'", charid), errbuf, NULL, &affected_rows);
	if(query)
	{
		safe_delete_array(query);
		query = NULL;
	}
	if(affected_rows != 1)	// here we have to have a match or it's an error
	{
		LogFile->write(EQEMuLog::Error, "DeleteCharacter: error: delete operation affected %d rows\n", affected_rows);
		return false;
	}
#if DEBUG >= 5
    printf(" keyring");
#endif
    RunQuery(query, MakeAnyLenString(&query, "DELETE FROM keyring WHERE char_id='%d'", charid), errbuf, NULL, &affected_rows);
    if(query)
    {
        safe_delete_array(query);
        query = NULL;
    }
#if DEBUG >= 5
	printf("\n");
#endif
	printf("DeleteCharacter: successfully deleted '%s' (id %d)\n", name, charid);

	return true;
}
// Store new character information into the character_ and inventory tables
bool Database::StoreCharacter(uint32 account_id, PlayerProfile_Struct* pp, Inventory* inv, ExtendedProfile_Struct *ext)
{
	_CP(Database_StoreCharacter);
	char errbuf[MYSQL_ERRMSG_SIZE];
	char query[256+sizeof(PlayerProfile_Struct)*2+sizeof(ExtendedProfile_Struct)*2+5];
	char* end = query;
	int32 affected_rows = 0;
	int i;
	int32 charid = 0;
	char* charidquery = 0;
	char* invquery = 0;
	MYSQL_RES *result;
	MYSQL_ROW row = 0;
	char zone[50];
	float x, y, z;

//	memset(&playeraa, 0, sizeof(playeraa));

	// get the char id (used in inventory inserts below)
	if(!RunQuery
	(
		charidquery,
		MakeAnyLenString
		(
			&charidquery,
			"SELECT id FROM character_ where name='%s'",
			pp->name
		),
		errbuf,
		&result
	)) {
		LogFile->write(EQEMuLog::Error, "Error in char store id query: %s: %s", charidquery, errbuf);
		return(false);
	}
	safe_delete_array(charidquery);

	if(mysql_num_rows(result) == 1)
	{
		row = mysql_fetch_row(result);
		if(row[0])
			charid = atoi(row[0]);
	}

	if(!charid)
	{
		LogFile->write(EQEMuLog::Error, "StoreCharacter: no character id");
		return false;
	}

	const char *zname = GetZoneName(pp->zone_id);
	if(zname == NULL) {
		//zone not in the DB, something to prevent crash...
		strncpy(zone, "qeynos", 49);
		pp->zone_id = 1;
	} else
		strncpy(zone, zname, 49);
	x=pp->x;
	y=pp->y;
	z=pp->z;

	// construct the character_ query
	end += sprintf(end,
		"UPDATE character_ SET timelaston=0, "
		"zonename=\'%s\', x=%f, y=%f, z=%f, profile=\'",
		zone, x, y, z
	);
	end += DoEscapeString(end, (char*)pp, sizeof(PlayerProfile_Struct));
	end += sprintf(end, "\', extprofile=\'");
	end += DoEscapeString(end, (char*)ext, sizeof(ExtendedProfile_Struct));
	end += sprintf(end, "\' WHERE account_id=%d AND name='%s'",account_id, pp->name);

	RunQuery(query, (int32) (end - query), errbuf, 0, &affected_rows);

	if(!affected_rows)
	{
		LogFile->write(EQEMuLog::Error, "StoreCharacter query '%s' %s", query, errbuf);
		return false;
	}

	affected_rows = 0;


	// Doodman: Is this even used?
	// now the inventory

	for (i=0; i<=2270;)
	{
		const ItemInst* newinv = inv->GetItem((sint16)i);
		if (newinv)
		{
			MakeAnyLenString
			(
				&invquery,
				"INSERT INTO inventory SET "
				"charid=%0u, slotid=%0d, itemid=%0u, charges=%0d, color=%0u",
				charid, i, newinv->GetItem()->ID,
				newinv->GetCharges(), newinv->GetColor()
			);

			RunQuery(invquery, strlen(invquery), errbuf, 0, &affected_rows);
			if(!affected_rows)
			{
				LogFile->write(EQEMuLog::Error, "StoreCharacter inventory failed.  Query '%s' %s", invquery, errbuf);
			}
			safe_delete_array(invquery);
#if EQDEBUG >= 9
			else
			{
				LogFile->write(EQEMuLog::Debug, "StoreCharacter inventory succeeded.  Query '%s' %s", invquery, errbuf);
			}
#endif
		}

		if(i==30){ //end of standard inventory/cursor, jump to internals of bags/cursor
			i = 251;
			continue;
		} else if(i==340){ //end of internals of bags/cursor, jump to bank slots
			i = 2000;
			continue;
		} else if(i==2023){ //end of bank slots, jump to internals of bank bags
			i = 2031;
			continue;
		}

		i++;
	}

	return true;
}

//0=failure, otherwise returns the char ID for the given char name.
int32 Database::GetCharacterID(const char *name) {
	int32 cid = 0;
	if(GetAccountIDByChar(name, &cid) == 0)
		return(0);
	return(cid);
}

/*
This function returns the account_id that owns the character with
the name "name" or zero if no character with that name was found
Zero will also be returned if there is a database error.
*/
int32 Database::GetAccountIDByChar(const char* charname, int32* oCharID) {
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
    MYSQL_RES *result;
    MYSQL_ROW row;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT account_id, id FROM character_ WHERE name='%s'", charname), errbuf, &result)) {
		safe_delete_array(query);
		if (mysql_num_rows(result) == 1)
		{
			row = mysql_fetch_row(result);
			int32 tmp = atoi(row[0]); // copy to temp var because gotta free the result before exitting this function
			if (oCharID)
				*oCharID = atoi(row[1]);
			mysql_free_result(result);
			return tmp;
		}
		mysql_free_result(result);
	}
	else {
		cerr << "Error in GetAccountIDByChar query '" << query << "' " << errbuf << endl;
		safe_delete_array(query);
	}

	return 0;
}

// Retrieve account_id for a given char_id
uint32 Database::GetAccountIDByChar(uint32 char_id) {
	char errbuf[MYSQL_ERRMSG_SIZE];
    char* query = 0;
    MYSQL_RES *result;
    MYSQL_ROW row;
	uint32 ret = 0;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT account_id FROM character_ WHERE id=%i", char_id), errbuf, &result)) {
		if (mysql_num_rows(result) == 1) {
			row = mysql_fetch_row(result);
			ret = atoi(row[0]); // copy to temp var because gotta free the result before exitting this function
		}
		mysql_free_result(result);
	}
	else {
		LogFile->write(EQEMuLog::Error, "Error in GetAccountIDByChar query '%s': %s", query, errbuf);
	}

	safe_delete_array(query);
	return ret;
}

int32 Database::GetAccountIDByName(const char* accname, sint16* status, int32* lsid) {
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
    MYSQL_RES *result;
    MYSQL_ROW row;


	for (unsigned int i=0; i<strlen(accname); i++) {
		if ((accname[i] < 'a' || accname[i] > 'z') &&
			(accname[i] < 'A' || accname[i] > 'Z') &&
			(accname[i] < '0' || accname[i] > '9'))
			return 0;
	}

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT id, status, lsaccount_id FROM account WHERE name='%s'", accname), errbuf, &result)) {
		safe_delete_array(query);
		if (mysql_num_rows(result) == 1) {
			row = mysql_fetch_row(result);
			int32 tmp = atoi(row[0]); // copy to temp var because gotta free the result before exitting this function
			if (status)
				*status = atoi(row[1]);
			if (lsid) {
				if (row[2])
					*lsid = atoi(row[2]);
				else
					*lsid = 0;
			}
			mysql_free_result(result);
			return tmp;
		}
		mysql_free_result(result);
	}
	else {
		cerr << "Error in GetAccountIDByAcc query '" << query << "' " << errbuf << endl;
		safe_delete_array(query);
	}

	return 0;
}

void Database::GetAccountName(int32 accountid, char* name, int32* oLSAccountID) {
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
    MYSQL_RES *result;
    MYSQL_ROW row;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT name, lsaccount_id FROM account WHERE id='%i'", accountid), errbuf, &result)) {
		safe_delete_array(query);
		if (mysql_num_rows(result) == 1) {
			row = mysql_fetch_row(result);

			strcpy(name, row[0]);
			if (row[1] && oLSAccountID) {
				*oLSAccountID = atoi(row[1]);
			}
		}

		mysql_free_result(result);
	}
	else {
		safe_delete_array(query);
		cerr << "Error in GetAccountName query '" << query << "' " << errbuf << endl;
	}
}

void Database::GetCharName(int32 char_id, char* name) {
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
    MYSQL_RES *result;
    MYSQL_ROW row;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT name FROM character_ WHERE id='%i'", char_id), errbuf, &result)) {
		safe_delete_array(query);
		if (mysql_num_rows(result) == 1) {
			row = mysql_fetch_row(result);

			strcpy(name, row[0]);
		}

		mysql_free_result(result);
	}
	else {
		safe_delete_array(query);
		cerr << "Error in GetCharName query '" << query << "' " << errbuf << endl;
	}

}

bool Database::LoadVariables() {
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
    MYSQL_RES *result;

	if (RunQuery(query, LoadVariables_MQ(&query), errbuf, &result)) {
		safe_delete_array(query);
		bool ret = LoadVariables_result(result);
		mysql_free_result(result);
		return ret;
	}
	else {
		cerr << "Error in LoadVariables query '" << query << "' " << errbuf << endl;
		safe_delete_array(query);
	}
	return false;
}

int32 Database::LoadVariables_MQ(char** query) {
// the read of this single variable should be atomic... this was causing strange problems
//	LockMutex lock(&Mvarcache);
	return MakeAnyLenString(query, "SELECT varname, value, unix_timestamp() FROM variables where unix_timestamp(ts) >= %d", varcache_lastupdate);
}

bool Database::LoadVariables_result(MYSQL_RES* result) {
	int32 i;
    MYSQL_ROW row;
	LockMutex lock(&Mvarcache);
	if (mysql_num_rows(result) > 0) {
		if (!varcache_array) {
			varcache_max = mysql_num_rows(result);
			varcache_array = new VarCache_Struct*[varcache_max];
			for (i=0; i<varcache_max; i++)
				varcache_array[i] = 0;
		}
		else {
			int32 tmpnewmax = varcache_max + mysql_num_rows(result);
			VarCache_Struct** tmp = new VarCache_Struct*[tmpnewmax];
			for (i=0; i<tmpnewmax; i++)
				tmp[i] = 0;
			for (i=0; i<varcache_max; i++)
				tmp[i] = varcache_array[i];
			VarCache_Struct** tmpdel = varcache_array;
			varcache_array = tmp;
			varcache_max = tmpnewmax;
			delete tmpdel;
		}
		while ((row = mysql_fetch_row(result))) {
			varcache_lastupdate = atoi(row[2]);
			for (i=0; i<varcache_max; i++) {
				if (varcache_array[i]) {
					if (strcasecmp(varcache_array[i]->varname, row[0]) == 0) {
						delete varcache_array[i];
						varcache_array[i] = (VarCache_Struct*) new int8[sizeof(VarCache_Struct) + strlen(row[1]) + 1];
						strn0cpy(varcache_array[i]->varname, row[0], sizeof(varcache_array[i]->varname));
						strcpy(varcache_array[i]->value, row[1]);
						break;
					}
				}
				else {
					varcache_array[i] = (VarCache_Struct*) new int8[sizeof(VarCache_Struct) + strlen(row[1]) + 1];
					strcpy(varcache_array[i]->varname, row[0]);
					strcpy(varcache_array[i]->value, row[1]);
					break;
				}
			}
		}
		int32 max_used = 0;
		for (i=0; i<varcache_max; i++) {
			if (varcache_array[i]) {
				if (i > max_used)
					max_used = i;
			}
		}
		max_used++;
		varcache_max = max_used;
	}
	return true;
}

// Gets variable from 'variables' table
bool Database::GetVariable(const char* varname, char* varvalue, int16 varvalue_len) {
	varvalue[0] = '\0';

	LockMutex lock(&Mvarcache);
	if (strlen(varname) <= 1)
		return false;
	for (int32 i=0; i<varcache_max; i++) {

		if (varcache_array[i]) {
			if (strcasecmp(varcache_array[i]->varname, varname) == 0) {
				snprintf(varvalue, varvalue_len, "%s", varcache_array[i]->value);
				varvalue[varvalue_len-1] = 0;
				return true;
			}
		}
		else
			return false;
	}
	return false;
}

bool Database::SetVariable(const char* varname_in, const char* varvalue_in) {
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
	int32 affected_rows = 0;

	char *varname,*varvalue;

	varname=(char *)malloc(strlen(varname_in)*2+1);
	varvalue=(char *)malloc(strlen(varvalue_in)*2+1);
	DoEscapeString(varname, varname_in, strlen(varname_in));
	DoEscapeString(varvalue, varvalue_in, strlen(varvalue_in));

	if (RunQuery(query, MakeAnyLenString(&query, "Update variables set value='%s' WHERE varname like '%s'", varvalue, varname), errbuf, 0, &affected_rows)) {
		safe_delete_array(query);
		if (affected_rows == 1) {
			LoadVariables(); // refresh cache
			free(varname);
			free(varvalue);
			return true;
		}
		else {
			if (RunQuery(query, MakeAnyLenString(&query, "Insert Into variables (varname, value) values ('%s', '%s')", varname, varvalue), errbuf, 0, &affected_rows)) {
				safe_delete_array(query);
				if (affected_rows == 1) {
					LoadVariables(); // refresh cache
					free(varname);
					free(varvalue);
					return true;
				}
			}
		}
	}
	else {
		cerr << "Error in SetVariable query '" << query << "' " << errbuf << endl;
		safe_delete_array(query);
	}
	free(varname);
	free(varvalue);
	return false;
}

int32 Database::GetMiniLoginAccount(char* ip){
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
    MYSQL_RES *result;
	MYSQL_ROW row;
	int32 retid = 0;
	if (RunQuery(query, MakeAnyLenString(&query, "SELECT id FROM account WHERE minilogin_ip='%s'", ip), errbuf, &result)) {
		safe_delete_array(query);
		if ((row = mysql_fetch_row(result)))
			retid = atoi(row[0]);
		mysql_free_result(result);
	}
	else
	{
		cerr << "Error in GetMiniLoginAccount query '" << query << "' " << errbuf << endl;
		safe_delete_array(query);
	}
	return retid;
}

// Pyro: Get zone starting points from DB
bool Database::GetSafePoints(const char* short_name, float* safe_x, float* safe_y, float* safe_z, sint16* minstatus, int8* minlevel, char *flag_needed, int8* canzone) { //Angelox4
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
	//	int buf_len = 256;
	//    int chars = -1;
    MYSQL_RES *result;
    MYSQL_ROW row;

	if (RunQuery(query, MakeAnyLenString(&query,
		"SELECT safe_x, safe_y, safe_z, min_status, min_level, "
		" flag_needed, canzone FROM zone " //Angelox4
		" WHERE short_name='%s'", short_name), errbuf, &result)) {
		safe_delete_array(query);
		if (mysql_num_rows(result) == 1) {
			row = mysql_fetch_row(result);
			if (safe_x != 0)
				*safe_x = atof(row[0]);
			if (safe_y != 0)
				*safe_y = atof(row[1]);
			if (safe_z != 0)
				*safe_z = atof(row[2]);
			if (minstatus != 0)
				*minstatus = atoi(row[3]);
			if (minlevel != 0)
				*minlevel = atoi(row[4]);
			if (flag_needed != NULL)
				strcpy(flag_needed, row[5]);
			if (canzone != 0) //Angelox4
				*canzone = atoi(row[6]); //Angelox4
			mysql_free_result(result);
			return true;
		}

		mysql_free_result(result);
	}
	else
	{
		cerr << "Error in GetSafePoint query '" << query << "' " << errbuf << endl;
		cerr << "If it errors, run the following querys:\n";
		cerr << "ALTER TABLE `zone` CHANGE `minium_level` `min_level` TINYINT(3)  UNSIGNED DEFAULT \"0\" NOT NULL;\n";
		cerr << "ALTER TABLE `zone` CHANGE `minium_status` `min_status` TINYINT(3)  UNSIGNED DEFAULT \"0\" NOT NULL;\n";
		cerr << "ALTER TABLE `zone` ADD flag_needed VARCHAR(128) NOT NULL DEFAULT '';\n";

		safe_delete_array(query);
	}
	return false;
}


bool Database::GetZoneLongName(const char* short_name, char** long_name, char* file_name, float* safe_x, float* safe_y, float* safe_z, int32* graveyard_id, int32* maxclients) {
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
    MYSQL_RES *result;
    MYSQL_ROW row;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT long_name, file_name, safe_x, safe_y, safe_z, graveyard_id, maxclients FROM zone WHERE short_name='%s'", short_name), errbuf, &result))
	{
		safe_delete_array(query);
		if (mysql_num_rows(result) == 1) {
			row = mysql_fetch_row(result);
			if (long_name != 0) {
				*long_name = strcpy(new char[strlen(row[0])+1], row[0]);
			}
			if (file_name != 0) {
				if (row[1] == 0)
					strcpy(file_name, short_name);
				else
					strcpy(file_name, row[1]);
			}
			if (safe_x != 0)
				*safe_x = atof(row[2]);
			if (safe_y != 0)
				*safe_y = atof(row[3]);
			if (safe_z != 0)
				*safe_z = atof(row[4]);
			if (graveyard_id != 0)
				*graveyard_id = atoi(row[5]);
			if (maxclients)
				*maxclients = atoi(row[6]);
			mysql_free_result(result);
			return true;
		}
		mysql_free_result(result);
	}
	else
	{
		cerr << "Error in GetZoneLongName query '" << query << "' " << errbuf << endl;
		safe_delete_array(query);
		return false;
	}

	return false;
}
int32 Database::GetZoneGraveyardID(int32 zone_id) {
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
    MYSQL_RES *result;
    MYSQL_ROW row;
    int32 GraveyardID = 0;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT graveyard_id FROM zone WHERE zoneidnumber='%u'", zone_id), errbuf, &result))
	{
		if (mysql_num_rows(result) == 1) {
			row = mysql_fetch_row(result);
			GraveyardID = atoi(row[0]);
		}
		mysql_free_result(result);
	}
	else
	{
		cerr << "Error in GetZoneGraveyardID query '" << query << "' " << errbuf << endl;
	}
	safe_delete_array(query);
	return GraveyardID;
}
bool Database::GetZoneGraveyard(const int32 graveyard_id, int32* graveyard_zoneid, float* graveyard_x, float* graveyard_y, float* graveyard_z, float* graveyard_heading) {
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
    MYSQL_RES *result;
    MYSQL_ROW row;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT zone_id, x, y, z, heading FROM graveyard WHERE id=%i", graveyard_id), errbuf, &result))
	{
		safe_delete_array(query);
		if (mysql_num_rows(result) == 1) {
			row = mysql_fetch_row(result);
			if(graveyard_zoneid != 0)
				*graveyard_zoneid = atoi(row[0]);
			if(graveyard_x != 0)
				*graveyard_x = atof(row[1]);
			if(graveyard_y != 0)
				*graveyard_y = atof(row[2]);
			if(graveyard_z != 0)
				*graveyard_z = atof(row[3]);
			if(graveyard_heading != 0)
				*graveyard_heading = atof(row[4]);
			mysql_free_result(result);
			return true;
		}
		mysql_free_result(result);
	}
	else
	{
		cerr << "Error in GetZoneGraveyard query '" << query << "' " << errbuf << endl;
		safe_delete_array(query);
		return false;
	}

	return false;
}

bool Database::LoadZoneNames() {
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
    MYSQL_RES *result;
    MYSQL_ROW row;
	query = new char[256];
	strcpy(query, "SELECT MAX(zoneidnumber) FROM zone");

	if (RunQuery(query, strlen(query), errbuf, &result)) {
		safe_delete_array(query);
		row = mysql_fetch_row(result);
		if (row && row[0])
		{
			max_zonename = atoi(row[0]);
			zonename_array = new char*[max_zonename+1];
			for(unsigned int i=0; i<max_zonename; i++) {
				zonename_array[i] = 0;
			}
			mysql_free_result(result);

			MakeAnyLenString(&query, "SELECT zoneidnumber, short_name FROM zone");
			if (RunQuery(query, strlen(query), errbuf, &result)) {
				safe_delete_array(query);
				while((row = mysql_fetch_row(result))) {
					zonename_array[atoi(row[0])] = new char[strlen(row[1]) + 1];
					strcpy(zonename_array[atoi(row[0])], row[1]);
					Sleep(0);
				}
				mysql_free_result(result);
			}
			else {
				cerr << "Error in LoadZoneNames query '" << query << "' " << errbuf << endl;
				safe_delete_array(query);
				return false;
			}
		}
		else {
			mysql_free_result(result);
		}
	}
	else {
		cerr << "Error in LoadZoneNames query '" << query << "' " << errbuf << endl;
		safe_delete_array(query);
		return false;
	}
	return true;
}

int32 Database::GetZoneID(const char* zonename) {
	if (zonename_array == 0)
		return 0;
	if (zonename == 0)
		return 0;
	for (unsigned int i=0; i<=max_zonename; i++) {
		if (zonename_array[i] != 0 && strcasecmp(zonename_array[i], zonename) == 0) {
			return i;
		}
	}
	return 0;
}

const char* Database::GetZoneName(int32 zoneID, bool ErrorUnknown) {
	if (zonename_array == 0) {
		if (ErrorUnknown)
			return "UNKNOWN";
		else
			return 0;
	}
	
	if (zoneID <= max_zonename) {
  		if (zonename_array[zoneID])
  			return zonename_array[zoneID];
  		else {
  			if (ErrorUnknown)
  				return "UNKNOWN";
  			else
  				return 0;
  		}
  	}
	else {
		if (ErrorUnknown)
			return "UNKNOWN";
		else
			return 0;
	}
	return 0;
}

int8 Database::GetPEQZone(int32 zoneID){
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
    MYSQL_RES *result;
	MYSQL_ROW row;
	int peqzone=0;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT peqzone from zone where zoneidnumber='%i'", zoneID), errbuf, &result)) 
	{
		if (mysql_num_rows(result) == 1) {
			row = mysql_fetch_row(result);
			peqzone = atoi(row[0]);
		}
			mysql_free_result(result);
		}
		else
		{
			cerr << "Error in GetPEQZone query '" << query << "' " << errbuf << endl;
	}
	safe_delete_array(query);
	return peqzone;
}

bool Database::CheckNameFilter(const char* name, bool surname) 
{
	std::string str_name = name;
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;

	if(surname)
	{
		// the minimum 4 is enforced by the client too
		if(!name || strlen(name) < 3)
		{
			return false;
		}
	}
	else
	{
		// the minimum 4 is enforced by the client too
		if(!name || strlen(name) < 4 || strlen(name) > 64)
		{
			return false;
		}
	}

	for (int i = 0; i < str_name.size(); i++)
	{
		if(!isalpha(str_name[i]))
		{
			return false;
		}
	}

	for(int x = 0; x < str_name.size(); ++x)
	{
		str_name[x] = tolower(str_name[x]);
	}

	char c = '\0';
	int8 num_c = 0;
	for(int x = 0; x < str_name.size(); ++x)
	{
		if(str_name[x] == c)
		{
			num_c++;
		}
		else
		{
			num_c = 1;
			c = str_name[x];
		}
		if(num_c > 2)
		{
			return false;
		}
	}

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT name FROM name_filter"), errbuf, &result)) {
		safe_delete_array(query);
		while(row = mysql_fetch_row(result))
		{
			std::string current_row = row[0];
			for(int x = 0; x < current_row.size(); ++x)
			{
				current_row[x] = tolower(current_row[x]);
			}

			if(str_name.find(current_row) != std::string::npos)
			{
				return false;
			}
		}

		mysql_free_result(result);
		return true;
	}
	else
	{
		cerr << "Error in CheckNameFilter query '" << query << "' " << errbuf << endl;
		safe_delete_array(query);
	}

	return true;
}

bool Database::AddToNameFilter(const char* name) {
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
	int32 affected_rows = 0;

	if (!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO name_filter (name) values ('%s')", name), errbuf, 0, &affected_rows)) {
		cerr << "Error in AddToNameFilter query '" << query << "' " << errbuf << endl;
		safe_delete_array(query);
		return false;
	}

	safe_delete_array(query);

	if (affected_rows == 0) {
		return false;
	}

	return true;
}

int32 Database::GetAccountIDFromLSID(int32 iLSID, char* oAccountName, sint16* oStatus) {
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
    MYSQL_RES *result;
    MYSQL_ROW row;
    
#ifdef DUAL_SERVER
	if (RunQuery(query, MakeAnyLenString(&query, "SELECT id, name, status FROM account WHERE lsaccount_id2=%i OR lsaccount_id=%i", iLSID, iLSID), errbuf, &result))
#else
	if (RunQuery(query, MakeAnyLenString(&query, "SELECT id, name, status FROM account WHERE lsaccount_id=%i", iLSID), errbuf, &result))
#endif

	{
		safe_delete_array(query);
		if (mysql_num_rows(result) == 1) {
			row = mysql_fetch_row(result);
			int32 account_id = atoi(row[0]);
			if (oAccountName)
				strcpy(oAccountName, row[1]);
			if (oStatus)
				*oStatus = atoi(row[2]);
			mysql_free_result(result);
			return account_id;
		}
		else
		{
			mysql_free_result(result);
			return 0;
		}
		mysql_free_result(result);
	}
	else {
		cerr << "Error in GetAccountIDFromLSID query '" << query << "' " << errbuf << endl;
		safe_delete_array(query);
		return 0;
	}

	return 0;
}

void Database::GetAccountFromID(int32 id, char* oAccountName, sint16* oStatus) {
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
    MYSQL_RES *result;
    MYSQL_ROW row;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT name, status FROM account WHERE id=%i", id), errbuf, &result))
	{
		if (mysql_num_rows(result) == 1) {
			row = mysql_fetch_row(result);
			if (oAccountName)
				strcpy(oAccountName, row[0]);
			if (oStatus)
				*oStatus = atoi(row[1]);
		}
		mysql_free_result(result);
	}
	else
		cerr << "Error in GetAccountFromID query '" << query << "' " << errbuf << endl;
	safe_delete_array(query);
}

void Database::ClearMerchantTemp(){
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;

	if (!RunQuery(query, MakeAnyLenString(&query, "delete from merchantlist_temp"), errbuf)) {
		cerr << "Error in ClearMerchantTemp query '" << query << "' " << errbuf << endl;
	}
	safe_delete_array(query);
}

bool Database::UpdateName(const char* oldname, const char* newname) {
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
	int32	affected_rows = 0;

	cout << "Renaming " << oldname << " to " << newname << "..." << endl;
	if (!RunQuery(query, MakeAnyLenString(&query, "UPDATE character_ SET name='%s' WHERE name='%s';", newname, oldname), errbuf, 0, &affected_rows)) {
		safe_delete_array(query);
		return false;
	}
	safe_delete_array(query);

	if (affected_rows == 0)
	{
		return false;
	}

	return true;
}

// If the name is used or an error occurs, it returns false, otherwise it returns true
bool Database::CheckUsedName(const char* name)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
    MYSQL_RES *result;
	//if (strlen(name) > 15)
	//	return false;
	if (!RunQuery(query, MakeAnyLenString(&query, "SELECT id FROM character_ where name='%s'", name), errbuf, &result)) {
		cerr << "Error in CheckUsedName query '" << query << "' " << errbuf << endl;
		safe_delete_array(query);
		return false;
	}
	else { // It was a valid Query, so lets do our counts!
		safe_delete_array(query);
		int32 tmp = mysql_num_rows(result);
		mysql_free_result(result);
		if (tmp > 0) // There is a Name!  No change (Return False)
			return false;
		else // Everything is okay, so we go and do this.
			return true;
	}
}

int8 Database::GetServerType()
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;
	if (RunQuery(query, MakeAnyLenString(&query, "SELECT value FROM variables WHERE varname='ServerType'"), errbuf, &result)) {
		safe_delete_array(query);
		if (mysql_num_rows(result) == 1)
		{
			row = mysql_fetch_row(result);
			int8 ServerType = atoi(row[0]);
			mysql_free_result(result);
			return ServerType;
		}
		else
		{
			mysql_free_result(result);
			return 0;
		}
		mysql_free_result(result);
	}
	else

	{


		cerr << "Error in GetServerType query '" << query << "' " << errbuf << endl;
		safe_delete_array(query);
		return false;
	}

	return 0;

}

bool Database::MoveCharacterToZone(const char* charname, const char* zonename,int32 zoneid) {
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	int32	affected_rows = 0;

	if(zonename == NULL || strlen(zonename) == 0)
		return(false);

	if (!RunQuery(query, MakeAnyLenString(&query, "UPDATE character_ SET zonename = '%s',zoneid=%i,x=-1, y=-1, z=-1 WHERE name='%s'", zonename,zoneid, charname), errbuf, 0,&affected_rows)) {
		cerr << "Error in MoveCharacterToZone(name) query '" << query << "' " << errbuf << endl;
		return false;
	}
	safe_delete_array(query);

	if (affected_rows == 0)
		return false;

	return true;
}

bool Database::MoveCharacterToZone(const char* charname, const char* zonename) {
	return MoveCharacterToZone(charname, zonename, GetZoneID(zonename));
}

bool Database::MoveCharacterToZone(int32 iCharID, const char* iZonename) {
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	int32	affected_rows = 0;
	if (!RunQuery(query, MakeAnyLenString(&query, "UPDATE character_ SET zonename = '%s', zoneid=%i, x=-1, y=-1, z=-1 WHERE id=%i", iZonename, GetZoneID(iZonename), iCharID), errbuf, 0,&affected_rows)) {
		cerr << "Error in MoveCharacterToZone(id) query '" << query << "' " << errbuf << endl;
		return false;
	}
	safe_delete_array(query);

	if (affected_rows == 0)
		return false;

	return true;
}

int8 Database::CopyCharacter(const char* oldname, const char* newname, int32 acctid) {
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;
	PlayerProfile_Struct* pp;
	ExtendedProfile_Struct* ext;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT profile, guild, guildrank, extprofile FROM character_ WHERE name='%s'", oldname), errbuf, &result)) {
		safe_delete_array(query);

		row = mysql_fetch_row(result);

		pp = (PlayerProfile_Struct*)row[0];
		strcpy(pp->name, newname);

		ext = (ExtendedProfile_Struct*)row[3];

		mysql_free_result(result);
	}

	else {
		cerr << "Error in CopyCharacter read query '" << query << "' " << errbuf << endl;
		safe_delete_array(query);
		return 0;
	}

	int32 affected_rows = 0;
	char query2[276 + sizeof(PlayerProfile_Struct)*2 + sizeof(ExtendedProfile_Struct)*2 + 1];
	char* end=query2;

	end += sprintf(end, "INSERT INTO character_ SET zonename=\'%s\', x = %f, y = %f, z = %f, profile=\'", GetZoneName(pp->zone_id), pp->x, pp->y, pp->z);
    end += DoEscapeString(end, (char*) pp, sizeof(PlayerProfile_Struct));
	end += sprintf(end,"\', extprofile=\'");
	end += DoEscapeString(end, (char*) ext, sizeof(ExtendedProfile_Struct));
    end += sprintf(end, "\', account_id=%d, name='%s'", acctid, newname);

	if (!RunQuery(query2, (int32) (end - query2), errbuf, 0, &affected_rows)) {
        cerr << "Error in CopyCharacter query '" << query << "' " << errbuf << endl;
		return 0;
    }

	// @merth: Need to copy inventory as well (and shared bank?)
	if (affected_rows == 0) {
		return 0;
	}

	return 1;
}

bool Database::SetHackerFlag(const char* accountname, const char* charactername, const char* hacked) {
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	int32	affected_rows = 0;
	if (!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO hackers(account,name,hacked) values('%s','%s','%s')", accountname, charactername, hacked), errbuf, 0,&affected_rows)) {
		cerr << "Error in SetHackerFlag query '" << query << "' " << errbuf << endl;
		return false;
	}
	safe_delete_array(query);

	if (affected_rows == 0)
	{
		return false;
	}

	return true;
}

bool Database::SetMQDetectionFlag(const char* accountname, const char* charactername, const char* hacked, const char* zone) { //Lieka:  Utilize the "hacker" table, but also give zone information.

	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	int32	affected_rows = 0;

	if (!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO hackers(account,name,hacked,zone) values('%s','%s','%s','%s')", accountname, charactername, hacked, zone), errbuf, 0,&affected_rows)) {
		cerr << "Error in SetMQDetectionFlag query '" << query << "' " << errbuf << endl;
		return false;
	}

	safe_delete_array(query);

	if (affected_rows == 0)
	{
		return false;
	}

	return true;
}

int8 Database::GetRaceSkill(int8 skillid, int8 in_race)
{
	int16 race_cap = 0;
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	int32	affected_rows = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;

	//Check for a racial cap!
	if (RunQuery(query, MakeAnyLenString(&query, "SELECT skillcap from race_skillcaps where skill = %i && race = %i", skillid, in_race), errbuf, &result, &affected_rows))
	{
		if (affected_rows != 0)
		{
			row = mysql_fetch_row(result);
			race_cap = atoi(row[0]);
		}
		delete[] query;
		mysql_free_result(result);
	}

	return race_cap;
}

int8 Database::GetSkillCap(int8 skillid, int8 in_race, int8 in_class, int16 in_level)
{
	int8 skill_level = 0, skill_formula = 0;
	int16 base_cap = 0, skill_cap = 0, skill_cap2 = 0, skill_cap3 = 0;
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	int32	affected_rows = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;
	//Fetch the data from DB.
	if (RunQuery(query, MakeAnyLenString(&query, "SELECT level, formula, pre50cap, post50cap, post60cap from skillcaps where skill = %i && class = %i", skillid, in_class), errbuf, &result, &affected_rows))
	{
		if (affected_rows != 0)
		{
			row = mysql_fetch_row(result);
			skill_level = atoi(row[0]);
			skill_formula = atoi(row[1]);
			skill_cap = atoi(row[2]);
			if (atoi(row[3]) > skill_cap)
				skill_cap2 = (atoi(row[3])-skill_cap)/10; //Split the post-50 skill cap into difference between pre-50 cap and post-50 cap / 10 to determine amount of points per level.
			skill_cap3 = atoi(row[4]);
		}
		delete[] query;
		mysql_free_result(result);
	}

	int race_skill = GetRaceSkill(skillid,in_race);

	if (race_skill > 0 && (race_skill > skill_cap || skill_cap == 0 || in_level < skill_level))
		return race_skill;

	if (skill_cap == 0) //Can't train this skill at all.
		return 255; //Untrainable

	if (in_level < skill_level)
		return 254; //Untrained

	//Determine pre-51 level-based cap
	if (skill_formula > 0)
		base_cap = in_level*skill_formula+skill_formula;
	if (base_cap > skill_cap || skill_formula == 0)
		base_cap = skill_cap;
	//If post 50, add post 50 cap to base cap.
	if (in_level > 50 && skill_cap2 > 0)
		base_cap += skill_cap2*(in_level-50);
	//No cap should ever go above its post50cap
	if (skill_cap3 > 0 && base_cap > skill_cap3)
		base_cap = skill_cap3;
	//Base cap is now the max value at the person's level, return it!
	return base_cap;
}

int32 Database::GetCharacterInfo(const char* iName, int32* oAccID, int32* oZoneID, int32* oInstanceID, float* oX, float* oY, float* oZ) {
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
    MYSQL_RES *result;
    MYSQL_ROW row;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT id, account_id, zonename, instanceid, x, y, z FROM character_ WHERE name='%s'", iName), errbuf, &result)) {
		safe_delete_array(query);
		if (mysql_num_rows(result) == 1) {
			row = mysql_fetch_row(result);
			int32 charid = atoi(row[0]);
			if (oAccID)
				*oAccID = atoi(row[1]);
			if (oZoneID)
				*oZoneID = GetZoneID(row[2]);
			if(oInstanceID)
				*oInstanceID = atoi(row[3]);
			if (oX)
				*oX = atof(row[4]);
			if (oY)
				*oY = atof(row[5]);
			if (oZ)
				*oZ = atof(row[6]);
			mysql_free_result(result);
			return charid;
		}
		mysql_free_result(result);
	}
	else {
		cerr << "Error in GetCharacterInfo query '" << query << "' " << errbuf << endl;
		safe_delete_array(query);
	}
	return 0;
}

bool Database::UpdateLiveChar(char* charname,int32 lsaccount_id) {
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
	if (!RunQuery(query, MakeAnyLenString(&query, "UPDATE account SET charname='%s' WHERE id=%i;",charname, lsaccount_id), errbuf)) {
		cerr << "Error in UpdateLiveChar query '" << query << "' " << errbuf << endl;
		safe_delete_array(query);
		return false;
	}

	safe_delete_array(query);
	return true;
}

bool Database::GetLiveChar(int32 account_id, char* cname) {
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
    MYSQL_RES *result;
    MYSQL_ROW row;
	if (RunQuery(query, MakeAnyLenString(&query, "SELECT charname FROM account WHERE id=%i", account_id), errbuf, &result)) {
		safe_delete_array(query);
		if (mysql_num_rows(result) == 1) {
			row = mysql_fetch_row(result);
			strcpy(cname,row[0]);
			mysql_free_result(result);
			return true;
		}
		mysql_free_result(result);
	}
	else {
		cerr << "Error in GetLiveChar query '" << query << "' " << errbuf << endl;
		safe_delete_array(query);
	}

	return false;
}

void Database::SetLFP(int32 CharID, bool LFP) {

	char ErrBuf[MYSQL_ERRMSG_SIZE];
	char *Query = 0;

	if (!RunQuery(Query, MakeAnyLenString(&Query, "update character_ set lfp=%i where id=%i",LFP, CharID), ErrBuf))
		LogFile->write(EQEMuLog::Error, "Error updating LFP for character %i : %s", CharID, ErrBuf);

	safe_delete_array(Query);

}

void Database::SetLFG(int32 CharID, bool LFG) {

	char ErrBuf[MYSQL_ERRMSG_SIZE];
	char *Query = 0;

	if (!RunQuery(Query, MakeAnyLenString(&Query, "update character_ set lfg=%i where id=%i",LFG, CharID), ErrBuf))
		LogFile->write(EQEMuLog::Error, "Error updating LFP for character %i : %s", CharID, ErrBuf);

	safe_delete_array(Query);

}

void Database::AddReport(std::string who, std::string against, std::string lines)
{
	char ErrBuf[MYSQL_ERRMSG_SIZE];
	char *Query = 0;
	char *escape_str = new char[lines.size()*2+1];
	DoEscapeString(escape_str, lines.c_str(), lines.size());

	if (!RunQuery(Query, MakeAnyLenString(&Query, "INSERT INTO reports (name, reported, reported_text) VALUES('%s', '%s', '%s')", who.c_str(), against.c_str(), escape_str), ErrBuf))
		LogFile->write(EQEMuLog::Error, "Error adding a report for %s: %s", who.c_str(), ErrBuf);

	safe_delete_array(Query);
	safe_delete_array(escape_str);
}

void  Database::SetGroupID(const char* name,int32 id, int32 charid){
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
	if(id == 0){ //removing you from table
	if (!RunQuery(query, MakeAnyLenString(&query, "delete from group_id where charid=%i and name='%s'",charid, name), errbuf))
		printf("Unable to get group id: %s\n",errbuf);
	}
	else{
	if (!RunQuery(query, MakeAnyLenString(&query, "replace into group_id set charid=%i, groupid=%i, name='%s'",charid, id, name), errbuf))
		printf("Unable to get group id: %s\n",errbuf);
	}
#ifdef _EQDEBUG
	printf("Set group id on '%s' to %d\n", name, id);
#endif
	safe_delete_array(query);
}

void Database::ClearGroup(int32 gid) {
	ClearGroupLeader(gid);
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
	if(gid == 0) {  //clear all groups
		//if (!RunQuery(query, MakeAnyLenString(&query, "update group_id set groupid=0 where groupid!=0"), errbuf))
		if (!RunQuery(query, MakeAnyLenString(&query, "delete from group_id"), errbuf))
			printf("Unable to clear groups: %s\n",errbuf);
	} else {	//clear a specific group
		//if (!RunQuery(query, MakeAnyLenString(&query, "update group_id set groupid=0 where groupid = %lu", gid), errbuf))
		if (!RunQuery(query, MakeAnyLenString(&query, "delete from group_id where groupid = %lu", (unsigned long)gid), errbuf))
			printf("Unable to clear groups: %s\n",errbuf);
	}
	safe_delete_array(query);
}

int32 Database::GetGroupID(const char* name){
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
    MYSQL_RES *result;
	MYSQL_ROW row;
	int32 groupid=0;
	if (RunQuery(query, MakeAnyLenString(&query, "SELECT groupid from group_id where name='%s'", name), errbuf, &result)) {
		if((row = mysql_fetch_row(result)))
		{
			if(row[0])
				groupid=atoi(row[0]);
		}
		else
			printf("Unable to get group id, char not found!\n");
		mysql_free_result(result);
	}
	else
			printf("Unable to get group id: %s\n",errbuf);
	safe_delete_array(query);
	return groupid;
}

char* Database::GetGroupLeaderForLogin(const char* name,char* leaderbuf){
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
    MYSQL_RES *result;
	MYSQL_ROW row;
	PlayerProfile_Struct pp;
	if (RunQuery(query, MakeAnyLenString(&query, "SELECT profile from character_ where name='%s'", name), errbuf, &result)) {
		row = mysql_fetch_row(result);
		unsigned long* lengths = mysql_fetch_lengths(result);
		if (lengths[0] == sizeof(PlayerProfile_Struct)) {
			memcpy(&pp, row[0], sizeof(PlayerProfile_Struct));
			strcpy(leaderbuf,pp.groupMembers[0]);
		}
		mysql_free_result(result);
	}
	else{
			printf("Unable to get leader name: %s\n",errbuf);
	}
	safe_delete_array(query);
	return leaderbuf;
}

void Database::SetGroupLeaderName(int32 gid, const char* name){
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
	if (!RunQuery(query, MakeAnyLenString(&query, "Replace into group_leaders set gid=%lu, leadername='%s'",(unsigned long)gid,name), errbuf))
		printf("Unable to set group leader: %s\n",errbuf);

	safe_delete_array(query);
}

char *Database::GetGroupLeadershipInfo(int32 gid, char* leaderbuf, char* assist, char *marknpc, GroupLeadershipAA_Struct* GLAA){
	char errbuf[MYSQL_ERRMSG_SIZE];
	char* query = 0;
	MYSQL_RES* result;
	MYSQL_ROW row;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT leadername, assist, marknpc, leadershipaa FROM group_leaders WHERE gid=%lu",(unsigned long)gid),
		     errbuf, &result)) {

		safe_delete_array(query);

		row = mysql_fetch_row(result);
		unsigned long* Lengths = mysql_fetch_lengths(result);

		if(row != NULL){

			if(leaderbuf)
				strcpy(leaderbuf, row[0]);

			if(assist)
				strcpy(assist, row[1]);

			if(marknpc)
				strcpy(marknpc, row[2]);

			if(GLAA && (Lengths[3] == sizeof(GroupLeadershipAA_Struct)))
				memcpy(GLAA, row[3], sizeof(GroupLeadershipAA_Struct));

			mysql_free_result(result);
			return leaderbuf;
		}
	}
	else
		safe_delete_array(query);

	if(leaderbuf)
		strcpy(leaderbuf, "UNKNOWN");

	if(assist)
		assist[0] = 0;

	if(marknpc)
		marknpc[0] = 0;

	return leaderbuf;
}

void Database::ClearGroupLeader(int32 gid){
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
	if(gid == 0) {  //clear all group leaders
		if (!RunQuery(query, MakeAnyLenString(&query, "DELETE from group_leaders"), errbuf))
			printf("Unable to clear group leaders: %s\n",errbuf);
	} else {	//clear a specific group leader
		if (!RunQuery(query, MakeAnyLenString(&query, "DELETE from group_leaders where gid = %lu", (unsigned long)gid), errbuf))
			printf("Unable to clear group leader: %s\n",errbuf);
	}
	safe_delete_array(query);
}

bool FetchRowMap(MYSQL_RES *result, map<string,string> &rowmap)
{
MYSQL_FIELD *fields;
MYSQL_ROW row;
unsigned long num_fields,i;
bool  retval=false;
	rowmap.clear();
	if (result && (num_fields=mysql_num_fields(result)) && (row = mysql_fetch_row(result))!=NULL && (fields = mysql_fetch_fields(result))!=NULL) {
		retval=true;
		for(i=0;i<num_fields;i++) {
			rowmap[fields[i].name]=(row[i] ? row[i] : "");
		}
	}

	return retval;
}

int8 Database::GetAgreementFlag(int32 acctid)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char* query = 0;
	MYSQL_RES* result;
	MYSQL_ROW row;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT rulesflag FROM account WHERE id=%i",acctid), errbuf, &result)) {
		safe_delete_array(query);
		if (mysql_num_rows(result) == 1)
		{
			row = mysql_fetch_row(result);
			int8 flag = atoi(row[0]);
			mysql_free_result(result);
			return flag;
		}
	}
	else
	{
		safe_delete_array(query);
	}
	return 0;
}

void Database::SetAgreementFlag(int32 acctid)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	int32	affected_rows = 0;

	if (!RunQuery(query, MakeAnyLenString(&query, "UPDATE account SET rulesflag=1 where id=%i",acctid), errbuf, 0, &affected_rows)) {
		safe_delete_array(query);
	}
	else
	safe_delete_array(query);
}

void Database::ClearRaid(int32 rid) {
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
	if(rid == 0) {  //clear all raids
		if (!RunQuery(query, MakeAnyLenString(&query, "delete from raid_members"), errbuf))
			printf("Unable to clear raids: %s\n",errbuf);
	} else {	//clear a specific group
		if (!RunQuery(query, MakeAnyLenString(&query, "delete from raid_members where raidid = %lu", (unsigned long)rid), errbuf))
			printf("Unable to clear raids: %s\n",errbuf);
	}
	safe_delete_array(query);
}

void Database::ClearRaidDetails(int32 rid) {
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
	if(rid == 0) {  //clear all raids
		if (!RunQuery(query, MakeAnyLenString(&query, "delete from raid_details"), errbuf))
			printf("Unable to clear raid details: %s\n",errbuf);
	} else {	//clear a specific group
		if (!RunQuery(query, MakeAnyLenString(&query, "delete from raid_details where raidid = %lu", (unsigned long)rid), errbuf))
			printf("Unable to clear raid details: %s\n",errbuf);
	}
	safe_delete_array(query);
}

int32 Database::GetRaidID(const char* name){
	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
    MYSQL_RES *result;
	MYSQL_ROW row;
	int32 raidid=0;
	if (RunQuery(query, MakeAnyLenString(&query, "SELECT raidid from raid_members where name='%s'", name), 
		errbuf, &result)) {
		if((row = mysql_fetch_row(result)))
		{
			if(row[0])
				raidid=atoi(row[0]);
		}
		else
			printf("Unable to get raid id, char not found!\n");
		mysql_free_result(result);
	}
	else
			printf("Unable to get raid id: %s\n",errbuf);
	safe_delete_array(query);
	return raidid;
}

const char *Database::GetRaidLeaderName(int32 rid)
{
	static char name[128];

	char errbuf[MYSQL_ERRMSG_SIZE];
    char *query = 0;
    MYSQL_RES *result;
	MYSQL_ROW row;
	
	if (RunQuery(query, MakeAnyLenString(&query, "SELECT name FROM raid_members WHERE raidid=%u AND israidleader=1", 
		rid), errbuf, &result)) {
		if((row = mysql_fetch_row(result)) != NULL)
		{
			memset(name, 0, 128);
			strcpy(name, row[0]);
			mysql_free_result(result);
			safe_delete_array(query);
			return name;
		}
		else
			printf("Unable to get raid id, char not found!\n");
		mysql_free_result(result);
	}
	else
		printf("Unable to get raid id: %s\n",errbuf);
	safe_delete_array(query);
	return "UNKNOWN";
}

bool Database::VerifyInstanceAlive(int16 instance_id, int32 char_id)
{

	//we are not saved to this instance so set our instance to 0
	if(!CharacterInInstanceGroup(instance_id, char_id))
	{
		SetCharacterInstance(0, char_id);
		return false;
	}

	if(CheckInstanceExpired(instance_id))
	{
		DeleteInstance(instance_id);
		SetCharacterInstance(0, char_id);
		return false;
	}
	return true;
}

bool Database::VerifyZoneInstance(int32 zone_id, int16 instance_id)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT id FROM instance_lockout where id=%u AND zone=%u", 
		instance_id, zone_id), errbuf, &result))
	{
		safe_delete_array(query);
		if (mysql_num_rows(result) != 0) 
		{
			mysql_free_result(result);
			return true;
		}
		else
		{
			mysql_free_result(result);
			return false;
		}
	}
	else 
	{
		safe_delete_array(query);
		return false;
	}
	return false;
}

bool Database::CharacterInInstanceGroup(int16 instance_id, int32 char_id)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	bool lockout_instance_player = false;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT charid FROM instance_lockout_player where id=%u AND charid=%u", 
		instance_id, char_id), errbuf, &result))
	{
		safe_delete_array(query);
		if (mysql_num_rows(result) == 1) 
		{
			lockout_instance_player = true;
		}
		mysql_free_result(result);
	}
	else 
	{
		safe_delete_array(query);
	}
	return lockout_instance_player;
}

void Database::SetCharacterInstance(int16 instance_id, int32 char_id)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	if(RunQuery(query, MakeAnyLenString(&query, "UPDATE character_ SET instanceid=%u WHERE id=%u", instance_id, 
		char_id), errbuf, &result))
	{
		safe_delete_array(query);
		mysql_free_result(result);
	}
	else 
	{
		safe_delete_array(query);
	}
}

void Database::DeleteInstance(uint16 instance_id)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;

	if(RunQuery(query, MakeAnyLenString(&query, "DELETE FROM instance_lockout WHERE id=%u", instance_id), errbuf))
	{
		safe_delete_array(query);
	}
	else 
	{
		safe_delete_array(query);
	}

	if(RunQuery(query, MakeAnyLenString(&query, "DELETE FROM instance_lockout_player WHERE id=%u", instance_id), errbuf))
	{
		safe_delete_array(query);
	}
	else 
	{
		safe_delete_array(query);
	}

	if(RunQuery(query, MakeAnyLenString(&query, "DELETE FROM respawn_times WHERE instance_id=%u", instance_id), errbuf))
	{
		safe_delete_array(query);
	}
	else 
	{
		safe_delete_array(query);
	}
	BuryCorpsesInInstance(instance_id);
}

bool Database::CheckInstanceExpired(uint16 instance_id)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;

	int32 start_time = 0;
	int32 duration = 0;
	if (RunQuery(query, MakeAnyLenString(&query, "SELECT start_time, duration FROM instance_lockout WHERE id=%u", 
		instance_id), errbuf, &result))
	{
		safe_delete_array(query);
		if (mysql_num_rows(result) != 0) 
		{
			row = mysql_fetch_row(result);
			start_time = atoi(row[0]);
			duration = atoi(row[1]);
		}
		else
		{
			mysql_free_result(result);
			return true;
		}
		mysql_free_result(result);
	}
	else 
	{
		safe_delete_array(query);
		return true;
	}

	timeval tv;
	gettimeofday(&tv, NULL);
	if((start_time + duration) <= tv.tv_sec)
	{
		return true;
	}
	return false;
}

int32 Database::ZoneIDFromInstanceID(uint16 instance_id)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int32 ret;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT zone FROM instance_lockout where id=%u", instance_id), 
		errbuf, &result))
	{
		safe_delete_array(query);
		if (mysql_num_rows(result) != 0) 
		{
			row = mysql_fetch_row(result);
			ret = atoi(row[0]);
			mysql_free_result(result);
			return ret;			
		}
		else
		{
			mysql_free_result(result);
			return 0;
		}
	}
	else 
	{
		safe_delete_array(query);
		return 0;
	}
	return 0;
}

int32 Database::VersionFromInstanceID(uint16 instance_id)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int32 ret;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT version FROM instance_lockout where id=%u", instance_id), 
		errbuf, &result))
	{
		safe_delete_array(query);
		if (mysql_num_rows(result) != 0) 
		{
			row = mysql_fetch_row(result);
			ret = atoi(row[0]);
			mysql_free_result(result);
			return ret;			
		}
		else
		{
			mysql_free_result(result);
			return 0;
		}
	}
	else 
	{
		safe_delete_array(query);
		return 0;
	}
	return 0;
}

int32 Database::GetTimeRemainingInstance(uint16 instance_id)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int32 start_time = 0;
	int32 duration = 0;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT start_time, duration FROM instance_lockout WHERE id=%u", 
		instance_id), errbuf, &result))
	{
		safe_delete_array(query);
		if (mysql_num_rows(result) != 0) 
		{
			row = mysql_fetch_row(result);
			start_time = atoi(row[0]);
			duration = atoi(row[1]);
		}
		else
		{
			mysql_free_result(result);
			return 0;
		}
		mysql_free_result(result);
	}
	else 
	{
		safe_delete_array(query);
		return 0;
	}

	timeval tv;
	gettimeofday(&tv, NULL);
	return ((start_time + duration) - tv.tv_sec);
}

bool Database::GetUnusedInstanceID(uint16 &instance_id)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT COUNT(*) FROM instance_lockout"), errbuf, &result))
	{
		safe_delete_array(query);
		if (mysql_num_rows(result) != 0) 
		{
			row = mysql_fetch_row(result);
			int count = atoi(row[0]);
			if(count == 0)
			{
				mysql_free_result(result);
				instance_id = 1;
				return true;
			}
		}
		else
		{
			mysql_free_result(result);
		}
		mysql_free_result(result);
	}
	else 
	{
		safe_delete_array(query);
		instance_id = 0;
		return false;
	}

	int32 count = 1;
	int32 max = 65535;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT id FROM instance_lockout ORDER BY id"), errbuf, &result))
	{
		safe_delete_array(query);
		if (mysql_num_rows(result) != 0) 
		{
			while(row = mysql_fetch_row(result))
			{
				if(count < atoi(row[0]))
				{
					instance_id = count;
					mysql_free_result(result);
					return true;
				}
				else if(count > max)
				{
					instance_id = 0;
					mysql_free_result(result);
					return false;
				}
				else
				{
					count++;
				}
			}
		}
		else
		{
			mysql_free_result(result);
		}
		mysql_free_result(result);
	}
	else 
	{
		safe_delete_array(query);
	}
	instance_id = count;
	return true;
}

//perhaps purge any expireds too
bool Database::CreateInstance(uint16 instance_id, uint32 zone_id, uint32 version, uint32 duration)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;

	if(RunQuery(query, MakeAnyLenString(&query, "INSERT INTO instance_lockout (id, zone, version, start_time, duration)" 
		" values(%lu, %lu, %lu, UNIX_TIMESTAMP(), %lu)", (unsigned long)instance_id, (unsigned long)zone_id, (unsigned long)version, (unsigned long)duration), errbuf))
	{
		safe_delete_array(query);
		return true;
	}
	else 
	{
		safe_delete_array(query);
		return false;
	}
}

void Database::PurgeExpiredInstances()
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;

	int16 id = 0;
	if (RunQuery(query, MakeAnyLenString(&query, "SELECT id FROM instance_lockout where "
			"(start_time+duration)<=UNIX_TIMESTAMP()"), errbuf, &result))
	{
		safe_delete_array(query);
		if (mysql_num_rows(result) > 0) 
		{
			row = mysql_fetch_row(result);
			while(row != NULL)
			{
				id = atoi(row[0]);
				DeleteInstance(id);
				row = mysql_fetch_row(result);
			}
		}
		mysql_free_result(result);
	}
	else 
	{
		safe_delete_array(query);
	}
}

bool Database::AddClientToInstance(uint16 instance_id, uint32 char_id)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;

	if(RunQuery(query, MakeAnyLenString(&query, "INSERT INTO instance_lockout_player(id, charid) "
			"values(%lu, %lu)", (unsigned long)instance_id, (unsigned long)char_id), errbuf))
	{
		safe_delete_array(query);
		return true;
	}
	else 
	{
		safe_delete_array(query);
		return false;
	}
}

bool Database::RemoveClientFromInstance(uint16 instance_id, uint32 char_id)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;

	if(RunQuery(query, MakeAnyLenString(&query, "DELETE FROM instance_lockout_player WHERE id=%lu AND charid=%lu", 
		(unsigned long)instance_id, (unsigned long)char_id), errbuf))
	{
		safe_delete_array(query);
		return true;
	}
	else 
	{
		safe_delete_array(query);
		return false;
	}
}

bool Database::RemoveClientsFromInstance(uint16 instance_id)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;

	if(RunQuery(query, MakeAnyLenString(&query, "DELETE FROM instance_lockout_player WHERE id=%lu", 
		(unsigned long)instance_id), errbuf))
	{
		safe_delete_array(query);
		return true;
	}
	else 
	{
		safe_delete_array(query);
		return false;
	}
}

bool Database::CheckInstanceExists(uint16 instance_id)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT * FROM instance_lockout where id=%u", instance_id), 
		errbuf, &result))
	{
		safe_delete_array(query);
		if (mysql_num_rows(result) != 0) 
		{
			mysql_free_result(result);
			return true;
		}
		mysql_free_result(result);
		return false;
	}
	else 
	{
		safe_delete_array(query);
		return false;
	}
	return false;
}

void Database::BuryCorpsesInInstance(uint16 instance_id)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;

	if(RunQuery(query, MakeAnyLenString(&query, "UPDATE player_corpses SET IsBurried=1, instanceid=0 WHERE instanceid=%u", 
		instance_id), errbuf, &result))
	{
		mysql_free_result(result);
	}
	safe_delete_array(query);
}

int16 Database::GetInstanceVersion(uint16 instance_id)
{
	if(instance_id < 1)
		return 0;

	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int32 ret;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT version FROM instance_lockout where id=%u", instance_id), 
		errbuf, &result))
	{
		safe_delete_array(query);
		if (mysql_num_rows(result) != 0) 
		{
			row = mysql_fetch_row(result);
			ret = atoi(row[0]);
			mysql_free_result(result);
			return ret;			
		}
		else
		{
			mysql_free_result(result);
			return 0;
		}
	}
	else 
	{
		safe_delete_array(query);
		return 0;
	}
	return 0;
}

int16 Database::GetInstanceID(const char* zone, int32 charid, int16 version)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int16 ret;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT instance_lockout.id FROM instance_lockout, instance_lockout_player "
		"WHERE instance_lockout.zone=%u AND instance_lockout.version=%u AND instance_lockout.id=instance_lockout_player.id AND "
		"instance_lockout_player.charid=%u LIMIT 1;", GetZoneID(zone), version, charid, charid), errbuf, &result))
	{
		safe_delete_array(query);
		if (mysql_num_rows(result) != 0) 
		{
			row = mysql_fetch_row(result);
			ret = atoi(row[0]);
			mysql_free_result(result);
			return ret;		
		}
		else
		{
			mysql_free_result(result);
			return 0;
		}
	}
	else 
	{
		safe_delete_array(query);
		return 0;
	}
	return 0;
}

int16 Database::GetInstanceID(int32 zone, int32 charid, int16 version)
{
	if(!zone)
		return 0;

	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int16 ret;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT instance_lockout.id FROM instance_lockout, instance_lockout_player "
		"WHERE instance_lockout.zone=%u AND instance_lockout.version=%u AND instance_lockout.id=instance_lockout_player.id AND "
		"instance_lockout_player.charid=%u LIMIT 1;", zone, version, charid), errbuf, &result))
	{
		safe_delete_array(query);
		if (mysql_num_rows(result) != 0) 
		{
			row = mysql_fetch_row(result);
			ret = atoi(row[0]);
			mysql_free_result(result);
			return ret;		
		}
		else
		{
			mysql_free_result(result);
			return 0;
		}
	}
	else 
	{
		safe_delete_array(query);
		return 0;
	}
	return 0;
}

void Database::AssignGroupToInstance(int32 gid, int32 instance_id)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int32 zone_id = ZoneIDFromInstanceID(instance_id);
	int16 version = VersionFromInstanceID(instance_id);

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT charid FROM group_id WHERE groupid=%u", gid), 
		errbuf, &result))
	{
		safe_delete_array(query);
		while((row = mysql_fetch_row(result)) != NULL)
		{
			int32 charid = atoi(row[0]);
			if(GetInstanceID(zone_id, charid, version) == 0)
			{
				AddClientToInstance(instance_id, charid);
			}
		}
		mysql_free_result(result);
	}
	else 
	{
		safe_delete_array(query);
	}
}

void Database::AssignRaidToInstance(int32 rid, int32 instance_id)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int32 zone_id = ZoneIDFromInstanceID(instance_id);
	int16 version = VersionFromInstanceID(instance_id);

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT charid FROM raid_members WHERE raidid=%u", rid), 
		errbuf, &result))
	{
		safe_delete_array(query);
		while((row = mysql_fetch_row(result)) != NULL)
		{
			int32 charid = atoi(row[0]);
			if(GetInstanceID(zone_id, charid, version) == 0)
			{
				AddClientToInstance(instance_id, charid);
			}
		}
		mysql_free_result(result);
	}
	else 
	{
		safe_delete_array(query);
	}
}

void Database::FlagInstanceByGroupLeader(int32 zone, int16 version, int32 charid, int32 gid)
{
	int16 id = GetInstanceID(zone, charid, version);
	if(id != 0)
		return;

	char ln[128];
	memset(ln, 0, 128);
	strcpy(ln, GetGroupLeadershipInfo(gid, ln));
	int32 l_charid = GetCharacterID((const char*)ln);
	int16 l_id = GetInstanceID(zone, l_charid, version);

	if(l_id == 0)
		return;

	AddClientToInstance(l_id, charid);
}

void Database::FlagInstanceByRaidLeader(int32 zone, int16 version, int32 charid, int32 rid)
{
	int16 id = GetInstanceID(zone, charid, version);
	if(id != 0)
		return;

	int32 l_charid = GetCharacterID(GetRaidLeaderName(rid));
	int16 l_id = GetInstanceID(zone, l_charid, version);

	if(l_id == 0)
		return;

	AddClientToInstance(l_id, charid);
}

void Database::SetInstanceDuration(int16 instance_id, int32 new_duration)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;

	if(RunQuery(query, MakeAnyLenString(&query, "UPDATE `instance_lockout` SET start_time=UNIX_TIMESTAMP(), "
		"duration=%u WHERE id=%u", new_duration, instance_id), errbuf))
	{
		safe_delete_array(query);
	}
	else
	{
		//error
		safe_delete_array(query);
	}
}

void Database::GroupAdventureLevelAndRange(int32 gid, int32 &avg_level, int32 &range)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int16 m_avg_level = 0;
	int8 num_in_group = 0;
	int16 min_level = 2000;
	int16 max_level = 0;

#ifndef GROUP_ADV_USE_VIEW
	if (RunQuery(query, MakeAnyLenString(&query, "SELECT character_.level FROM character_, group_id"
		" WHERE character_.id=group_id.charid AND group_id.groupid=%u", gid), errbuf, &result))
#else
	if (RunQuery(query, MakeAnyLenString(&query, "select level from vwGroups where groupid = %u", gid), errbuf, &result))
#endif
	{
		safe_delete_array(query);
		while((row = mysql_fetch_row(result)) != NULL)
		{
			int16 m_lvl = atoi(row[0]);
			m_avg_level += m_lvl;
			if(m_lvl < min_level)
				min_level = m_lvl;

			if(m_lvl > max_level)
				max_level = m_lvl;
			num_in_group++;
		}
		mysql_free_result(result);
	}
	else 
	{
		safe_delete_array(query);
	}
	avg_level = (m_avg_level / num_in_group);
	range = max_level-min_level;
}

void Database::RaidAdventureLevelAndRange(int32 rid, int32 &avg_level, int32 &range)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int16 m_avg_level = 0;
	int8 num_in_group = 0;
	int16 min_level = 2000;
	int16 max_level = 0;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT raid_members.level FROM raid_members "
		"WHERE raid_members.raidid=%u", rid), errbuf, &result))
	{
		safe_delete_array(query);
		while((row = mysql_fetch_row(result)) != NULL)
		{
			int16 m_lvl = atoi(row[0]);
			m_avg_level += m_lvl;
			if(m_lvl < min_level)
				min_level = m_lvl;

			if(m_lvl > max_level)
				max_level = m_lvl;
			num_in_group++;
		}
		mysql_free_result(result);
	}
	else 
	{
		safe_delete_array(query);
	}
	avg_level = (m_avg_level / num_in_group);
	range = max_level-min_level;
}

int32 Database::CreateAdventure(int32 adventure_id)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	int32 affected_rows = 0;
	int32 last_insert_id = 0;

    if (!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO `adventure_details` SET adventure_id=%u,"
		" time_created=UNIX_TIMESTAMP()", adventure_id), errbuf, 0, &affected_rows, &last_insert_id)) {
		safe_delete_array(query);
		return 0;
    }
	safe_delete_array(query);
	
	if (affected_rows == 0) 
	{
		return 0;
	}

	if (last_insert_id == 0) 
	{
		return 0;
	}
	return last_insert_id;
}

void Database::AddPlayerToAdventure(int32 id, int32 charid)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;

	if(RunQuery(query, MakeAnyLenString(&query, "INSERT INTO `adventure_members` SET"
		" id=%u, charid=%u", id, charid), errbuf))
	{
		safe_delete_array(query);
	}
	else
	{
		//error
		safe_delete_array(query);
	}
}

void Database::RemovePlayerFromAdventure(int32 id, int32 charid)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;

	if(RunQuery(query, MakeAnyLenString(&query, "DELETE FROM `adventure_members` WHERE"
		" id=%u AND charid=%u", id, charid), errbuf))
	{
		safe_delete_array(query);
	}
	else
	{
		//error
		safe_delete_array(query);
	}
}

void Database::RemovePlayersFromAdventure(int32 id)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;

	if(RunQuery(query, MakeAnyLenString(&query, "DELETE FROM `adventure_members` WHERE"
		" id=%u", id), errbuf))
	{
		safe_delete_array(query);
	}
	else
	{
		//error
		safe_delete_array(query);
	}
}

void Database::AddGroupToAdventure(int32 id, int32 gid)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT charid FROM group_id "
		"WHERE groupid=%u", gid), errbuf, &result))
	{
		safe_delete_array(query);
		while((row = mysql_fetch_row(result)) != NULL)
		{
			int32 charid = atoi(row[0]);
			AddPlayerToAdventure(id, charid);
		}
		mysql_free_result(result);
	}
	else 
	{
		safe_delete_array(query);
	}
}

void Database::AddRaidToAdventure(int32 id, int32 rid)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT charid FROM raid_members "
		"WHERE raidid=%u", rid), errbuf, &result))
	{
		safe_delete_array(query);
		while((row = mysql_fetch_row(result)) != NULL)
		{
			int32 charid = atoi(row[0]);
			AddPlayerToAdventure(id, charid);
		}
		mysql_free_result(result);
	}
	else 
	{
		safe_delete_array(query);
	}
}

void Database::DestroyAdventure(int32 id)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;

	if(RunQuery(query, MakeAnyLenString(&query, "DELETE FROM `adventure_details` WHERE id=%u", id), errbuf))
	{
		safe_delete_array(query);
	}
	else
	{
		//error
		safe_delete_array(query);
	}

	if(RunQuery(query, MakeAnyLenString(&query, "DELETE FROM `adventure_members` WHERE id=%u", id), errbuf))
	{
		safe_delete_array(query);
	}
	else
	{
		//error
		safe_delete_array(query);
	}
}

bool Database::GetAdventureDetails(int32 charid, int32 &id, int32 &adventure_id, int32 &instance_id, int32 &count, 
								   int32 &ass_count, int32 &status, int32 &time_c, int32 &time_z, int32 &time_comp)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int32 adv_id = 0;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT `id` FROM `adventure_members` WHERE charid=%u LIMIT 1", 
		charid), errbuf, &result))
	{
		safe_delete_array(query);
		while((row = mysql_fetch_row(result)) != NULL)
		{
			adv_id = atoi(row[0]);
		}
		mysql_free_result(result);
	}
	else 
	{
		safe_delete_array(query);
	}

	if(adv_id == 0)
		return false;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT `adventure_id`, `instance_id`, `count`, `assassinate_count`, `status`, "
		"`time_created`, `time_zoned`, `time_completed` FROM `adventure_details` WHERE id=%u LIMIT 1", adv_id), errbuf, &result))
	{
		safe_delete_array(query);
		while((row = mysql_fetch_row(result)) != NULL)
		{
			adventure_id = atoi(row[0]);
			instance_id = atoi(row[1]);
			count = atoi(row[2]);
			ass_count = atoi(row[3]);
			status = atoi(row[4]);
			time_c = atoi(row[5]);
			time_z = atoi(row[6]);
			time_comp = atoi(row[7]);
			id = adv_id;
		}
		mysql_free_result(result);
		return true;
	}
	else 
	{
		safe_delete_array(query);
		return false;
	}
}

int32 Database::GetAdventureID(int32 char_id)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int32 adv_id = 0;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT `id` FROM `adventure_members` WHERE charid=%u LIMIT 1", 
		char_id), errbuf, &result))
	{
		safe_delete_array(query);
		while((row = mysql_fetch_row(result)) != NULL)
		{
			adv_id = atoi(row[0]);
		}
		mysql_free_result(result);
	}
	else 
	{
		safe_delete_array(query);
	}
	return adv_id;
}

int32 Database::CountPlayersInAdventure(int32 id) 
{ 
	//SELECT `charid` FROM `adventure_members` WHERE id=%u
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;

	int count = 0;
	if (RunQuery(query, MakeAnyLenString(&query, "SELECT `charid` FROM `adventure_members` WHERE "
		"id=%u", id), errbuf, &result))
	{
		safe_delete_array(query);
		while((row = mysql_fetch_row(result)) != NULL)
		{
			count++;
		}
		mysql_free_result(result);
	}
	else 
	{
		safe_delete_array(query);
	}
	return count;
}

void Database::PurgeAdventures() 
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;

	if(RunQuery(query, MakeAnyLenString(&query, "DELETE FROM `adventure_details`"), errbuf))
	{
		safe_delete_array(query);
	}
	else
	{
		//error
		safe_delete_array(query);
	}

	if(RunQuery(query, MakeAnyLenString(&query, "DELETE FROM `adventure_members`"), errbuf))
	{
		safe_delete_array(query);
	}
	else
	{
		//error
		safe_delete_array(query);
	}
}

void Database::AddAdventureToInstance(int32 adv_id, int32 inst_id) 
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT `charid` FROM `adventure_members` WHERE id=%u", 
		adv_id), errbuf, &result))
	{
		safe_delete_array(query);
		while((row = mysql_fetch_row(result)) != NULL)
		{
			int32 id = atoi(row[0]);
			AddClientToInstance(inst_id, id);
		}
		mysql_free_result(result);
	}
	else 
	{
		safe_delete_array(query);
	}
}

void Database::UpdateAdventureStatus(int32 adv_id, int32 status) 
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	if(RunQuery(query, MakeAnyLenString(&query, "UPDATE `adventure_details` SET status=%u WHERE id=%u", 
		status, adv_id), errbuf))
	{
		safe_delete_array(query);
	}
	else
	{
		//error
		safe_delete_array(query);
	}
}

void Database::UpdateAdventureInstance(int32 adv_id, int32 inst_id, int32 time) 
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	if(RunQuery(query, MakeAnyLenString(&query, "UPDATE `adventure_details` SET instance_id=%d, "
		"time_zoned=%u WHERE id=%u", inst_id, time, adv_id), errbuf))
	{
		safe_delete_array(query);
	}
	else
	{
		//error
		safe_delete_array(query);
	}
}

void Database::UpdateAdventureCompleted(int32 adv_id, int32 time)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	if(RunQuery(query, MakeAnyLenString(&query, "UPDATE `adventure_details` SET time_completed=%u "
		"WHERE id=%u", time, adv_id), errbuf))
	{
		safe_delete_array(query);
	}
	else
	{
		//error
		safe_delete_array(query);
	}
}

void Database::UpdateAdventureCount(int32 adv_id, int32 new_count)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	if(RunQuery(query, MakeAnyLenString(&query, "UPDATE `adventure_details` SET count=%u "
		"WHERE id=%u", new_count, adv_id), errbuf))
	{
		safe_delete_array(query);
	}
	else
	{
		//error
		safe_delete_array(query);
	}
}

void Database::IncrementAdventureCount(int32 adv_id)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	if(RunQuery(query, MakeAnyLenString(&query, "UPDATE `adventure_details` SET count=count+1 "
		"WHERE id=%u", adv_id), errbuf))
	{
		safe_delete_array(query);
	}
	else
	{
		//error
		safe_delete_array(query);
	}
}

int32 Database::GetAdventureCount(int32 adv_id)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT `count` FROM `adventure_details` WHERE id=%u", 
		adv_id), errbuf, &result))
	{
		safe_delete_array(query);
		while((row = mysql_fetch_row(result)) != NULL)
		{
			int32 count = atoi(row[0]);
			return count;
		}
		mysql_free_result(result);
	}
	else 
	{
		safe_delete_array(query);
		return 0;
	}
	return 0;	
}

bool Database::AdventureExists(int32 adv_id)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT `id` FROM `adventure_details` WHERE id=%u", 
		adv_id), errbuf, &result))
	{
		safe_delete_array(query);
		while((row = mysql_fetch_row(result)) != NULL)
		{
			return true;
		}
		mysql_free_result(result);
	}
	else
	{
		safe_delete_array(query);
		return false;
	}
	return false;
}

void Database::UpdateAdventureStatsEntry(int32 char_id, int8 theme, bool win)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	int32 affected = 0;

	std::string field;

	if(win)
	{
		switch(theme)
		{
			case 1:
			{
				field = "guk_wins";
				break;
			}
			case 2:
			{
				field = "mir_wins";
				break;
			}
			case 3:
			{
				field = "mmc_wins";
				break;
			}
			case 4:
			{
				field = "ruj_wins";
				break;
			}
			case 5:
			{
				field = "tak_wins";
				break;
			}
			default:
			{
				return;
			}
		}
	}
	else
	{
		switch(theme)
		{
			case 1:
			{
				field = "guk_losses";
				break;
			}
			case 2:
			{
				field = "mir_losses";
				break;
			}
			case 3:
			{
				field = "mmc_losses";
				break;
			}
			case 4:
			{
				field = "ruj_losses";
				break;
			}
			case 5:
			{
				field = "tak_losses";
				break;
			}
			default:
			{
				return;
			}
		}
	}

		if(RunQuery(query, MakeAnyLenString(&query, "UPDATE `adventure_stats` SET %s=%s+1 WHERE player_id=%u",
		field.c_str(), field.c_str(), char_id), errbuf, NULL, &affected))
		{
			safe_delete_array(query);
		}
		else
		{
			//error
			safe_delete_array(query);
		}

	if(affected == 0)
	{
		if(RunQuery(query, MakeAnyLenString(&query, "INSERT INTO `adventure_stats` SET %s=1, player_id=%u",
			field.c_str(), char_id), errbuf))
		{
			safe_delete_array(query);
		}
		else
		{
			//error
			safe_delete_array(query);
		}
	}
}

void Database::UpdateAllAdventureStatsEntry(int32 adv_id, int8 theme, bool win)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;

	if(!AdventureExists(adv_id))
		return;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT `charid` FROM `adventure_members` WHERE id=%u", 
		adv_id), errbuf, &result))
	{
		safe_delete_array(query);
		while((row = mysql_fetch_row(result)) != NULL)
		{
			int32 charid = atoi(row[0]);
			UpdateAdventureStatsEntry(charid, theme, win);
		}
		mysql_free_result(result);
	}
	else
	{
		safe_delete_array(query);
	}
}

bool Database::GetAdventureStats(int32 char_id, int32 &guk_w, int32 &mir_w, int32 &mmc_w, int32 &ruj_w, 
								 int32 &tak_w, int32 &guk_l, int32 &mir_l, int32 &mmc_l, int32 &ruj_l, int32 &tak_l)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT `guk_wins`, `mir_wins`, `mmc_wins`, `ruj_wins`, `tak_wins`, "
		"`guk_losses`, `mir_losses`, `mmc_losses`, `ruj_losses`, `tak_losses` FROM `adventure_stats` WHERE player_id=%u", 
		char_id), errbuf, &result))
	{
		safe_delete_array(query);
		while((row = mysql_fetch_row(result)) != NULL)
		{
			guk_w = atoi(row[0]);
			mir_w = atoi(row[1]);
			mmc_w = atoi(row[2]);
			ruj_w = atoi(row[3]);
			tak_w = atoi(row[4]);
			guk_l = atoi(row[5]);
			mir_l = atoi(row[6]);
			mmc_l = atoi(row[7]);
			ruj_l = atoi(row[8]);
			tak_l = atoi(row[9]);
		}
		mysql_free_result(result);
		return true;
	}
	else 
	{
		safe_delete_array(query);
		return false;
	}
}

int32 Database::AdventureGetAssassinateKills(int32 adv_id)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int32 ret_val = 0;

	if (RunQuery(query, MakeAnyLenString(&query, "SELECT `assassinate_count` FROM"
		" `adventure_details` WHERE id=%u", adv_id), errbuf, &result))
	{
		safe_delete_array(query);
		while((row = mysql_fetch_row(result)) != NULL)
		{
			ret_val = atoi(row[0]);
		}
		mysql_free_result(result);
		return ret_val;
	}
	else 
	{
		safe_delete_array(query);
		return ret_val;
	}
}

void Database::AdventureSetAssassinateKills(int32 adv_id, int32 kills)
{
	char errbuf[MYSQL_ERRMSG_SIZE];
	char *query = 0;
	if(RunQuery(query, MakeAnyLenString(&query, "UPDATE `adventure_details` SET assassinate_count=%u "
		"WHERE id=%u", kills, adv_id), errbuf))
	{
		safe_delete_array(query);
	}
	else
	{
		//error
		safe_delete_array(query);
	}
}
database.h
Code:
#ifndef EQEMU_DATABASE_H
#define EQEMU_DATABASE_H

#define AUTHENTICATION_TIMEOUT	60
#define INVALID_ID				0xFFFFFFFF

#include "debug.h"
#include "types.h"
#include "dbcore.h"
#include "linked_list.h"
#include "eq_packet_structs.h"
/*#include "EQStream.h"
#include "guilds.h"
#include "MiscFunctions.h"
#include "Mutex.h"
#include "Item.h"
#include "extprofile.h"*/
#include <string>
#include <vector>
#include <map>
using namespace std;

//atoi is not int32 or uint32 safe!!!!
#define atoul(str) strtoul(str, NULL, 10)

//class Spawn;
class Corpse;
class Spawn2;
class NPC;
class SpawnGroupList;
class Petition;
class Client;
struct Combine_Struct;
//struct Faction;
//struct FactionMods;
//struct FactionValue;
struct ZonePoint;
struct NPCType;
class Inventory;
class ItemInst;

struct EventLogDetails_Struct {
	int32	id;
	char	accountname[64];
	int32	account_id;
	sint16	status;
	char	charactername[64];
	char	targetname[64];
	char	timestamp[64];
	char	descriptiontype[64];
	char	details[128];
};

struct CharacterEventLog_Struct {
int32	count;
int8	eventid;
EventLogDetails_Struct eld[255];
};


// Added By Hogie 
// INSERT into variables (varname,value) values('decaytime [minlevel] [maxlevel]','[number of seconds]');
// IE: decaytime 1 54 = Levels 1 through 54
//     decaytime 55 100 = Levels 55 through 100
// It will always put the LAST time for the level (I think) from the Database
struct npcDecayTimes_Struct {
	int16 minlvl;
	int16 maxlvl;
	int32 seconds;
};
// Added By Hogie -- End

struct VarCache_Struct {
	char varname[26];	// varname is char(25) in database
	char value[0];
};

struct PlayerProfile_Struct;
struct GuildRankLevel_Struct;
struct GuildRanks_Struct;
struct ExtendedProfile_Struct;
struct GuildMember_Struct;
class PTimerList;

class Database : public DBcore {
public:
	Database();
	Database(const char* host, const char* user, const char* passwd, const char* database,int32 port);
	bool Connect(const char* host, const char* user, const char* passwd, const char* database,int32 port);
	~Database();
	
	
//	void	ExtraOptions();
	

	/*
	 * General Character Related Stuff
	 */
	bool	MoveCharacterToZone(const char* charname, const char* zonename);
	bool	MoveCharacterToZone(const char* charname, const char* zonename,int32 zoneid);
	bool	MoveCharacterToZone(int32 iCharID, const char* iZonename);
	bool	UpdateName(const char* oldname, const char* newname);
	bool	SetHackerFlag(const char* accountname, const char* charactername, const char* hacked);
	bool	SetMQDetectionFlag(const char* accountname, const char* charactername, const char* hacked, const char* zone);
	bool	AddToNameFilter(const char* name);
	bool	ReserveName(int32 account_id, char* name);
	bool	CreateCharacter(uint32 account_id, char* name, int16 gender, int16 race, int16 class_, int8 str, int8 sta, int8 cha, int8 dex, int8 int_, int8 agi, int8 wis, int8 face);
	bool	StoreCharacter(uint32 account_id, PlayerProfile_Struct* pp, Inventory* inv, ExtendedProfile_Struct *ext);
	bool	DeleteCharacter(char* name);
	int8	CopyCharacter(const char* oldname, const char* newname, int32 acctid);

	/*
	 * General Information Getting Queries
	 */
	bool	CheckNameFilter(const char* name, bool surname = false);
	bool	CheckUsedName(const char* name);
	int32	GetAccountIDByChar(const char* charname, int32* oCharID = 0);
	uint32	GetAccountIDByChar(uint32 char_id);
	int32	GetAccountIDByName(const char* accname, sint16* status = 0, int32* lsid = 0);
	void	GetAccountName(int32 accountid, char* name, int32* oLSAccountID = 0);
	void	GetCharName(int32 char_id, char* name);
	int32	GetCharacterInfo(const char* iName, int32* oAccID = 0, int32* oZoneID = 0, int32* oInstanceID = 0,float* oX = 0, float* oY = 0, float* oZ = 0);
	int32	GetCharacterID(const char *name);
	bool	CheckBannedIPs(const char* loginIP); //Lieka Edit:  Check incomming connection against banned IP table.
 	bool	AddBannedIP(char* bannedIP, const char* notes); //Lieka Edit:  Add IP address to the Banned_IPs table.
	bool	CheckGMIPs(const char* loginIP, int32 account_id);
	bool	AddGMIP(char* ip_address, char* name);
	void	LoginIP(int32 AccountID, const char* LoginIP);

	/*
	 * Instancing Stuff
	 */
	bool VerifyZoneInstance(int32 zone_id, int16 instance_id);
	bool VerifyInstanceAlive(int16 instance_id, int32 char_id);
	bool CharacterInInstanceGroup(int16 instance_id, int32 char_id);
	void SetCharacterInstance(int16 instance_id, int32 char_id);
	void DeleteInstance(uint16 instance_id);
	bool CheckInstanceExpired(uint16 instance_id);
	int32 ZoneIDFromInstanceID(uint16 instance_id);
	int32 VersionFromInstanceID(uint16 instance_id);
	int32 GetTimeRemainingInstance(uint16 instance_id);
	bool GetUnusedInstanceID(uint16 &instance_id);
	bool CreateInstance(uint16 instance_id, uint32 zone_id, uint32 version, uint32 duration);
	void PurgeExpiredInstances();
	bool AddClientToInstance(uint16 instance_id, uint32 char_id);
	bool RemoveClientFromInstance(uint16 instance_id, uint32 char_id);
	bool RemoveClientsFromInstance(uint16 instance_id);
	bool CheckInstanceExists(uint16 instance_id);
	void BuryCorpsesInInstance(uint16 instance_id);
	int16 GetInstanceVersion(uint16 instance_id);
	int16 GetInstanceID(const char* zone, int32 charid, int16 version);
	int16 GetInstanceID(int32 zone, int32 charid, int16 version);
	void AssignGroupToInstance(int32 gid, int32 instance_id);
	void AssignRaidToInstance(int32 rid, int32 instance_id);
	void FlagInstanceByGroupLeader(int32 zone, int16 version, int32 charid, int32 gid);
	void FlagInstanceByRaidLeader(int32 zone, int16 version, int32 charid, int32 rid);
	void SetInstanceDuration(int16 instance_id, int32 new_duration);

	/*
	 * Adventure
	 */
	void GroupAdventureLevelAndRange(int32 gid, int32 &avg_level, int32 &range);
	void RaidAdventureLevelAndRange(int32 rid, int32 &avg_level, int32 &range);
	int32 CreateAdventure(int32 adventure_id);
	void AddPlayerToAdventure(int32 id, int32 charid);
	void RemovePlayerFromAdventure(int32 id, int32 charid);
	void RemovePlayersFromAdventure(int32 id);
	void AddGroupToAdventure(int32 id, int32 gid);
	void AddRaidToAdventure(int32 id, int32 rid);
	void DestroyAdventure(int32 id);
	bool GetAdventureDetails(int32 charid, int32 &id, int32 &adventure_id, int32 &instance_id, int32 &count, 
		int32 &ass_count, int32 &status, int32 &time_c, int32 &time_z, int32 &time_comp);
	int32 GetAdventureID(int32 char_id);
	int32 CountPlayersInAdventure(int32 id);
	void PurgeAdventures();
	void AddAdventureToInstance(int32 adv_id, int32 inst_id);
	void UpdateAdventureStatus(int32 adv_id, int32 status);
	void UpdateAdventureInstance(int32 adv_id, int32 inst_id, int32 time);
	void UpdateAdventureCompleted(int32 adv_id, int32 time);
	void UpdateAdventureCount(int32 adv_id, int32 new_count);
	void IncrementAdventureCount(int32 adv_id);
	int32 GetAdventureCount(int32 adv_id);
	bool AdventureExists(int32 adv_id);
	void UpdateAdventureStatsEntry(int32 char_id, int8 theme, bool win);
	void UpdateAllAdventureStatsEntry(int32 adv_id, int8 theme, bool win);
	bool GetAdventureStats(int32 char_id, int32 &guk_w, int32 &mir_w, int32 &mmc_w, int32 &ruj_w, int32 &tak_w, 
		int32 &guk_l, int32 &mir_l, int32 &mmc_l, int32 &ruj_l, int32 &tak_l);
	int32 AdventureGetAssassinateKills(int32 adv_id);
	void AdventureSetAssassinateKills(int32 adv_id, int32 kills);

	/*
	 * Account Related
	 */
	int32	GetMiniLoginAccount(char* ip);
	void	GetAccountFromID(int32 id, char* oAccountName, sint16* oStatus);
	int32	CheckLogin(const char* name, const char* password, sint16* oStatus = 0);
	sint16	CheckStatus(int32 account_id);
#ifdef DUAL_SERVER
	int32	CreateAccount(const char* name, const char* password, sint16 status, int32 lsaccount_id = 0, int32 lsaccount_id2 = 0);
	int32	pLSID;
	inline int32		LSID()	const		{ return pLSID; }
#else
	int32	CreateAccount(const char* name, const char* password, sint16 status, int32 lsaccount_id = 0);
#endif

	bool	DeleteAccount(const char* name);
 	bool	SetAccountStatus(const char* name, sint16 status);
	bool	SetLocalPassword(uint32 accid, const char* password);
	int32	GetAccountIDFromLSID(int32 iLSID, char* oAccountName = 0, sint16* oStatus = 0);
	bool	UpdateLiveChar(char* charname,int32 lsaccount_id);
	bool	GetLiveChar(int32 account_id, char* cname);
	int8	GetAgreementFlag(int32 acctid);
	void	SetAgreementFlag(int32 acctid);
	
	/*
	 * Groups
	 */
	int32	GetGroupID(const char* name);
	void	SetGroupID(const char* name, int32 id, int32 charid);
	void	ClearGroup(int32 gid = 0);
	char*	GetGroupLeaderForLogin(const char* name,char* leaderbuf);
	
	void	SetGroupLeaderName(int32 gid, const char* name);
	char*	GetGroupLeadershipInfo(int32 gid, char* leaderbuf, char* assist = NULL, char *marknpc = NULL,
				       GroupLeadershipAA_Struct* GLAA = NULL);
	void	ClearGroupLeader(int32 gid = 0);

	/*
	 * Raids
	 */
	void	ClearRaid(int32 rid = 0);
	void	ClearRaidDetails(int32 rid = 0);
	int32	GetRaidID(const char* name);
	const char *GetRaidLeaderName(int32 rid);

	/*
	 * Database Varaibles
	 */
	bool	GetVariable(const char* varname, char* varvalue, int16 varvalue_len);
	bool	SetVariable(const char* varname, const char* varvalue);
	bool	LoadVariables();
	int32	LoadVariables_MQ(char** query);
	bool	LoadVariables_result(MYSQL_RES* result);
	
	/*
	 * General Queries
	 */
	bool	LoadZoneNames();
	bool	GetZoneLongName(const char* short_name, char** long_name, char* file_name = 0, float* safe_x = 0, float* safe_y = 0, float* safe_z = 0, int32* graveyard_id = 0, int32* maxclients = 0);
	bool	GetZoneGraveyard(const int32 graveyard_id, int32* graveyard_zoneid = 0, float* graveyard_x = 0, float* graveyard_y = 0, float* graveyard_z = 0, float* graveyard_heading = 0);
	int32	GetZoneGraveyardID(int32 zone_id);
	int32	GetZoneID(const char* zonename);
	int8    GetPEQZone(int32 zoneID);
	const char*	GetZoneName(int32 zoneID, bool ErrorUnknown = false);
	int8	GetServerType();
	bool	GetSafePoints(const char* short_name, float* safe_x = 0, float* safe_y = 0, float* safe_z = 0, sint16* minstatus = 0, int8* minlevel = 0, char *flag_needed = NULL, int8* canzone = 0); //Angelox4
	bool	GetSafePoints(int32 zoneID, float* safe_x = 0, float* safe_y = 0, float* safe_z = 0, sint16* minstatus = 0, int8* minlevel = 0, char *flag_needed = NULL, int8* canzone = 0) { return GetSafePoints(GetZoneName(zoneID), safe_x, safe_y, safe_z, minstatus, minlevel, flag_needed, canzone); } //Angelox4
	int8	GetSkillCap(int8 skillid, int8 in_race, int8 in_class, int16 in_level);
	int8	GetRaceSkill(int8 skillid, int8 in_race);
	
	bool	LoadPTimers(uint32 charid, PTimerList &into);
	void	ClearPTimers(uint32 charid);
	void	ClearMerchantTemp();
	void	SetLFP(int32 CharID, bool LFP); 
	void	SetLFG(int32 CharID, bool LFG); 
	void	AddReport(std::string who, std::string against, std::string lines);
	

protected:
	void	HandleMysqlError(int32 errnum);
	//bool	RunQuery(const char* query, int32 querylen, char* errbuf = 0, MYSQL_RES** result = 0, int32* affected_rows = 0, int32* errnum = 0, bool retry = true);
	
private:
	void DBInitVars();
	
	int32				max_zonename;
	char**				zonename_array;
	
	Mutex				Mvarcache;
	uint32				varcache_max;
	VarCache_Struct**	varcache_array;
	uint32				varcache_lastupdate;
};

bool	FetchRowMap(MYSQL_RES *result, map<string,string> &rowmap);
#endif
Reply With Quote
 


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump

   

All times are GMT -4. The time now is 05:21 PM.


 

Everquest is a registered trademark of Daybreak Game Company LLC.
EQEmulator is not associated or affiliated in any way with Daybreak Game Company LLC.
Except where otherwise noted, this site is licensed under a Creative Commons License.
       
Powered by vBulletin®, Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Template by Bluepearl Design and vBulletin Templates - Ver3.3