EQEmulator Forums

EQEmulator Forums (https://www.eqemulator.org/forums/index.php)
-   Development::Development (https://www.eqemulator.org/forums/forumdisplay.php?f=590)
-   -   Dual Login Server Code (https://www.eqemulator.org/forums/showthread.php?t=31072)

Angelox 04-17-2010 10:43 AM

Dual Login Server Code
 
Secrets: I cant find your original Dual Login server code, so here's what I wanted to add on to it, as it's a continuation of what you did. This has been working fine and I've had it it on since I saw your post a while back.
In summary, here's what happens; first i wanted to maintain separate ID records of my users, so I added another table to table account and called it lsaccount_id2. This is what I have on my notes so has two alterations;
Code:

ALTER TABLE `account` ADD `lsaccount_id2` int(10) UNSIGNED DEFAULT '0'AFTER `lsaccount_id`;
ALTER TABLE `ax_classic`.`account` MODIFY COLUMN `lsaccount_id2` INT(10) UNSIGNED DEFAULT 0;

Since account already had all the users, and I needed one table to start at a higher increment, I converted the original account table;
Code:

UPDATE ax_classic.account SET lsaccount_id=lsaccount_id +5000000 WHERE lsaccount_id > 0;
And my accounts on my LS to match;
Code:

UPDATE new_login.login_accounts SET id=id +5000000;
so now I have my LS and accounts pointed to anything 5000000 or above, and anything below 5000000, must be from EqEmu- I don't think EqEmu will reach 5000000 during my lifetime, but if it did, then just up the increment to my LS accounts.
I have two sets of code, one that I have in use, but since it is sort of "hackish", i wanted one that was true in all areas, one that would monitor and single out/specify each port. But it is a lot of work that goes into a lot of code (and the work is triple for me, because I never know what I'm doing most the time), I got burnt out an put it on my "ToDo" list.
Here's the code I currently use, changes to LS are quoted with DUAL_SERVER, so you can easily pull them out and add them to your code, I posted the whole pages of script, cause diffs won't work with this code, it has other custom stuff, but you can see where the Dual LS code is placed (#ifdef DUAL_SERVER);

LoginServer.cpp
Code:

#include "../common/debug.h"
#include <iostream>
using namespace std;
#include <string.h>
#include <stdio.h>
#include <iomanip>
using namespace std;
#include <stdlib.h>
#include "../common/version.h"

#ifdef WIN32
        #include <process.h>
        #include <windows.h>
        #include <winsock.h>

        #define snprintf        _snprintf
#if (_MSC_VER < 1500)
        #define vsnprintf        _vsnprintf
#endif
        #define strncasecmp        _strnicmp
        #define strcasecmp        _stricmp
#else // Pyro: fix for linux
        #include <sys/socket.h>
#ifdef FREEBSD //Timothy Whitman - January 7, 2003
        #include <sys/types.h>
#endif
        #include <netinet/in.h>
        #include <arpa/inet.h>
        #include <pthread.h>
        #include <unistd.h>
        #include <errno.h>

        #include "../common/unix.h"

        #define SOCKET_ERROR -1
        #define INVALID_SOCKET -1
        extern int errno;
#endif

#define IGNORE_LS_FATAL_ERROR

#include "../common/servertalk.h"
#include "LoginServer.h"
#include "../common/eq_packet_structs.h"
#include "../common/packet_dump.h"
#include "zoneserver.h"
#include "worlddb.h"
#include "zonelist.h"
#include "clientlist.h"
#include "WorldConfig.h"

extern ZSList zoneserver_list;
extern LoginServer loginserver;
extern ClientList client_list;
extern uint32 numzones;
extern int32 numplayers;
extern volatile bool        RunLoops;
volatile bool LoginLoopRunning = false;

bool AttemptingConnect = false;

#ifdef DUAL_SERVER
LoginServer::LoginServer(const char* iAddress, const char* iAddress2, int16 iPort, int16 iPort2)
#else
LoginServer::LoginServer(const char* iAddress, int16 iPort)
#endif

: statusupdate_timer(LoginServer_StatusUpdateInterval)
{
        LoginServerIP = ResolveIP(iAddress);
        LoginServerPort = iPort;
        tcpc = new EmuTCPConnection(true);
        tcpc->SetPacketMode(EmuTCPConnection::packetModeLogin);

#ifdef DUAL_SERVER  //Angelox
        LoginServerIP = ResolveIP(iAddress2);
        LoginServerPort = iPort2;
        tcpc2 = new EmuTCPConnection(true);
        tcpc2->SetPacketMode(EmuTCPConnection::packetModeLogin);
#endif

}

LoginServer::~LoginServer() {
        delete tcpc;

#ifdef DUAL_SERVER
        delete tcpc2;
#endif

}

bool LoginServer::Process() {
        const WorldConfig *Config=WorldConfig::get();

        if (statusupdate_timer.Check()) {
                this->SendStatus();
        }
   
        /************ Get all packets from packet manager out queue and process them ************/
        ServerPacket *pack = 0;

#ifdef DUAL_SERVER
        ServerPacket *pack2 = 0;
#endif

        while((pack = tcpc->PopPacket()))
        {
                _log(WORLD__LS_TRACE,"Recevied ServerPacket from LS OpCode 0x04x",pack->opcode);
                _hex(WORLD__LS_TRACE,pack->pBuffer,pack->size);

                switch(pack->opcode) {
                case 0:
                        break;
                case ServerOP_KeepAlive: {
                        // ignore this
                        break;
                }
                case ServerOP_UsertoWorldReq: {
                        UsertoWorldRequest_Struct* utwr = (UsertoWorldRequest_Struct*) pack->pBuffer;       
                        int32 id = database.GetAccountIDFromLSID(utwr->lsaccountid);
                        sint16 status = database.CheckStatus(id);

                        ServerPacket* outpack = new ServerPacket;
                        outpack->opcode = ServerOP_UsertoWorldResp;
                        outpack->size = sizeof(UsertoWorldResponse_Struct);
                        outpack->pBuffer = new uchar[outpack->size];
                        memset(outpack->pBuffer, 0, outpack->size);
                        UsertoWorldResponse_Struct* utwrs = (UsertoWorldResponse_Struct*) outpack->pBuffer;
                        utwrs->lsaccountid = utwr->lsaccountid;
                        utwrs->ToID = utwr->FromID;

                        if(Config->Locked == true)
                        {
                                if((status == 0 || status < 100) && (status != -2 || status != -1))
                                        utwrs->response = 0;
                                if(status >= 100)
                                        utwrs->response = 1;
                        }
                        else {
                                utwrs->response = 1;
                        }

                        sint32 x = Config->MaxClients;
                        if( (sint32)numplayers >= x && x != -1 && x != 255 && status < 80)
                                utwrs->response = -3;

                        if(status == -1)
                                utwrs->response = -1;
                        if(status == -2)
                                utwrs->response = -2;

                        utwrs->worldid = utwr->worldid;
                        SendPacket(outpack);
                        delete outpack;
                        break;
                }
                case ServerOP_LSClientAuth: {
                        ServerLSClientAuth* slsca = (ServerLSClientAuth*) pack->pBuffer;

                        if (RuleI(World, AccountSessionLimit) >= 0) {
                                // Enforce the limit on the number of characters on the same account that can be
                                // online at the same time.
                                client_list.EnforceSessionLimit(slsca->lsaccount_id);
                        }

                        client_list.CLEAdd(slsca->lsaccount_id, slsca->name, slsca->key, slsca->worldadmin, slsca->ip, slsca->local);
                        break;
                }
                case ServerOP_LSFatalError: {
#ifndef IGNORE_LS_FATAL_ERROR
                        WorldConfig::DisableLoginserver();
                        _log(WORLD__LS_ERR, "Login server responded with FatalError. Disabling reconnect.");
#else
                _log(WORLD__LS_ERR, "Login server responded with FatalError.");
#endif
                        if (pack->size > 1) {
                                _log(WORLD__LS_ERR, "    %s",pack->pBuffer);
                        }
                        break;
                }
                case ServerOP_SystemwideMessage: {
                        ServerSystemwideMessage* swm = (ServerSystemwideMessage*) pack->pBuffer;
                        zoneserver_list.SendEmoteMessageRaw(0, 0, 0, swm->type, swm->message);
                        break;
                }
                case ServerOP_LSRemoteAddr: {
                        if (!Config->WorldAddress.length()) {
                                WorldConfig::SetWorldAddress((char *)pack->pBuffer);
                                _log(WORLD__LS, "Loginserver provided %s as world address",pack->pBuffer);
                        }
                        break;
                }
                default:
                {
                        _log(WORLD__LS_ERR, "Unknown LSOpCode: 0x%04x size=%d",(int)pack->opcode,pack->size);
DumpPacket(pack->pBuffer, pack->size);
                        break;
                }
                }

                delete pack;
        }

#ifdef DUAL_SERVER
                while((pack2 = tcpc2->PopPacket()))
        {
                _log(WORLD__LS_TRACE,"Recevied ServerPacket from LS OpCode 0x04x",pack2->opcode);
                _hex(WORLD__LS_TRACE,pack2->pBuffer,pack2->size);

                switch(pack2->opcode) {
                case 0:
                        break;
                case ServerOP_KeepAlive: {
                        // ignore this
                        break;
                }
                case ServerOP_UsertoWorldReq: {
                        UsertoWorldRequest_Struct* utwr = (UsertoWorldRequest_Struct*) pack2->pBuffer;       
                        int32 id = database.GetAccountIDFromLSID(utwr->lsaccountid);
                        sint16 status = database.CheckStatus(id);

                        ServerPacket* outpack = new ServerPacket;
                        outpack->opcode = ServerOP_UsertoWorldResp;
                        outpack->size = sizeof(UsertoWorldResponse_Struct);
                        outpack->pBuffer = new uchar[outpack->size];
                        memset(outpack->pBuffer, 0, outpack->size);
                        UsertoWorldResponse_Struct* utwrs = (UsertoWorldResponse_Struct*) outpack->pBuffer;
                        utwrs->lsaccountid = utwr->lsaccountid;
                        utwrs->ToID = utwr->FromID;

                        if(Config->Locked == true)
                        {
                                if((status == 0 || status < 100) && (status != -2 || status != -1))
                                        utwrs->response = 0;
                                if(status >= 100)
                                        utwrs->response = 1;
                        }
                        else {
                                utwrs->response = 1;
                        }

                        sint32 x = Config->MaxClients;
                        if( (sint32)numplayers >= x && x != -1 && x != 255 && status < 80)
                                utwrs->response = -3;

                        if(status == -1)
                                utwrs->response = -1;
                        if(status == -2)
                                utwrs->response = -2;

                        utwrs->worldid = utwr->worldid;
                        SendPacket2(outpack);
                        delete outpack;
                        break;
                }
                case ServerOP_LSClientAuth: {
                        ServerLSClientAuth* slsca = (ServerLSClientAuth*) pack2->pBuffer;

                        if (RuleI(World, AccountSessionLimit) >= 0) {
                                // Enforce the limit on the number of characters on the same account that can be
                                // online at the same time.
                                client_list.EnforceSessionLimit(slsca->lsaccount_id);
                        }

                        client_list.CLEAdd(slsca->lsaccount_id, slsca->name, slsca->key, slsca->worldadmin, slsca->ip, slsca->local);
                        break;
                }
                case ServerOP_LSFatalError: {
#ifndef IGNORE_LS_FATAL_ERROR
                        WorldConfig::DisableLoginserver();
                        _log(WORLD__LS_ERR, "Login server responded with FatalError. Disabling reconnect.");
#else
                _log(WORLD__LS_ERR, "Login server responded with FatalError.");
#endif
                        if (pack2->size > 1) {
                                _log(WORLD__LS_ERR, "    %s",pack2->pBuffer);
                        }
                        break;
                }
                case ServerOP_SystemwideMessage: {
                        ServerSystemwideMessage* swm = (ServerSystemwideMessage*) pack2->pBuffer;
                        zoneserver_list.SendEmoteMessageRaw(0, 0, 0, swm->type, swm->message);
                        break;
                }
                case ServerOP_LSRemoteAddr: {
                        if (!Config->WorldAddress.length()) {
                                WorldConfig::SetWorldAddress((char *)pack2->pBuffer);
                                _log(WORLD__LS, "Loginserver provided %s as world address",pack2->pBuffer);
                        }
                        break;
                }
                default:
                {
                        _log(WORLD__LS_ERR, "Unknown LSOpCode: 0x%04x size=%d",(int)pack2->opcode,pack->size);
DumpPacket(pack2->pBuffer, pack2->size);
                        break;
                }
                }

                delete pack2;
                }
#endif //END DUAL_SERVER

        return true;
}

// this should always be called in a new thread
#ifdef WIN32
        void AutoInitLoginServer(void *tmp) {
#else
        void *AutoInitLoginServer(void *tmp) {
#endif
        srand(time(NULL));

#ifdef DUAL_SERVER
        if (loginserver.ConnectReady() && loginserver.ConnectReady2()) {
#else
        if (loginserver.ConnectReady()) {
#endif

                InitLoginServer();
        }
#ifndef WIN32
        return 0;
#endif
}
//Start
bool InitLoginServer() {
#ifdef DUAL_SERVER
        _log(WORLD__LS, "Dual Connecting to the login servers...");
#else
        _log(WORLD__LS, "Connecting to login server...");
#endif
        const WorldConfig *Config=WorldConfig::get();

#ifdef DUAL_SERVER
        if ((!loginserver.ConnectReady()) || (!loginserver.ConnectReady2())) {
#else
        if (!loginserver.ConnectReady()) {
#endif

                _log(WORLD__LS_ERR,"InitLoginServer() while already attempting connect");
                return false;
        }
        if (!Config->LoginHost.length()) {
                _log(WORLD__LS_ERR,"Login server info not loaded");
                return false;
        }

        AttemptingConnect = true;

#ifdef DUAL_SERVER
        loginserver.Connect(Config->LoginHost.c_str(), Config->LoginPort, Config->LoginHost2.c_str(), Config->LoginPort2);
#else
        loginserver.Connect(Config->LoginHost.c_str(), Config->LoginPort);
#endif

        return true;
}

#ifdef DUAL_SERVER
bool LoginServer::Connect(const char* iAddress, int16 iPort, const char* iAddress2, int16 iPort2) {
#else
bool LoginServer::Connect(const char* iAddress, int16 iPort) {
#endif

        char tmp[25];
        if(database.GetVariable("loginType",tmp,sizeof(tmp)) && strcasecmp(tmp,"MinILogin") == 0){
                minilogin = true;
                _log(WORLD__LS, "Setting World to MiniLogin Server type");
        }
        else
                minilogin = false;

        if (minilogin && WorldConfig::get()->WorldAddress.length()==0) {
                _log(WORLD__LS_ERR, "**** For minilogin to work, you need to set the <address> element in the <world> section.");
                return false;
        }

        char errbuf[TCPConnection_ErrorBufferSize];

#ifdef DUAL_SERVER
        //char errbuf2[TCPConnection_ErrorBufferSize];
#endif

        if (iAddress == 0) {
                _log(WORLD__LS_ERR, "Null address given to LoginServer::Connect");
                return false;
        }
        else {
                if ((LoginServerIP = ResolveIP(iAddress, errbuf)) == 0)  {
                        _log(WORLD__LS_ERR, "Unable to resolve '%s' to an IP.",iAddress);
                        return false;
                }
        }
        if (iPort != 0)
                LoginServerPort = iPort;

        if (LoginServerIP == 0 || LoginServerPort == 0) {
                _log(WORLD__LS_ERR, "LoginServer::Connect: Connect info incomplete, cannot connect");
                return false;
        }

#ifdef DUAL_SERVER
        if (iAddress2 == 0) {
                _log(WORLD__LS_ERR, "Null address given to LoginServer::Connect");
                return false;
        }
        else {
                if ((LoginServerIP2 = ResolveIP(iAddress2, errbuf)) == 0) {
                        _log(WORLD__LS_ERR, "Unable to resolve '%s' to an IP.",iAddress2);
                        return false;
                }
        }
        if (iPort2 != 0)
                LoginServerPort2 = iPort2;

        if (LoginServerIP2 == 0 || LoginServerPort2 == 0) {
                _log(WORLD__LS_ERR, "LoginServer2::Connect: Connect info incomplete, cannot connect");
                return false;
        }


        if (tcpc->ConnectIP(LoginServerIP, LoginServerPort, errbuf) && tcpc2->ConnectIP(LoginServerIP2, LoginServerPort2, errbuf)) {
                _log(WORLD__LS, "Connected to EqEmu Loginserver: %s:%d",iAddress,LoginServerPort);
                _log(WORLD__LS, "Connected to AXClassic Loginserver: %s:%d",iAddress2,LoginServerPort2);
#else
        if (tcpc->ConnectIP(LoginServerIP, LoginServerPort, errbuf)) {
                _log(WORLD__LS, "Connected to Loginserver: %s:%d",iAddress,LoginServerPort);
#endif

                if (minilogin)
                        SendInfo();
                else
                        SendNewInfo();
                SendStatus();
                zoneserver_list.SendLSZones();
                return true;
        }
        else {

#ifdef DUAL_SERVER
                _log(WORLD__LS_ERR, "FATAL ERROR! - SERVERS NOT CONNECTED. One or more connections not esablished, so none are connected.",errbuf);
#else
                _log(WORLD__LS_ERR, "Could not connect to login server: %s",errbuf);
#endif

                return false;
        }
}
void LoginServer::SendInfo() {
        const WorldConfig *Config=WorldConfig::get();

        ServerPacket* pack = new ServerPacket;
        pack->opcode = ServerOP_LSInfo;
        pack->size = sizeof(ServerLSInfo_Struct);
        pack->pBuffer = new uchar[pack->size];
        memset(pack->pBuffer, 0, pack->size);
        ServerLSInfo_Struct* lsi = (ServerLSInfo_Struct*) pack->pBuffer;
        strcpy(lsi->protocolversion, EQEMU_PROTOCOL_VERSION);
        strcpy(lsi->serverversion, CURRENT_VERSION);
        strcpy(lsi->name, Config->LongName.c_str());
        strcpy(lsi->account, Config->LoginAccount.c_str());
        strcpy(lsi->password, Config->LoginPassword.c_str());
        strcpy(lsi->address, Config->WorldAddress.c_str());
        SendPacket(pack);

#ifdef DUAL_SERVER
        ServerPacket* pack2 = new ServerPacket;
        pack2->opcode = ServerOP_LSInfo;
        pack2->size = sizeof(ServerLSInfo_Struct);
        pack2->pBuffer = new uchar[pack2->size];
        memset(pack2->pBuffer, 0, pack2->size);
        ServerLSInfo_Struct* lsi2 = (ServerLSInfo_Struct*) pack2->pBuffer;
        strcpy(lsi2->protocolversion, EQEMU_PROTOCOL_VERSION);
        strcpy(lsi2->serverversion, CURRENT_VERSION);
        strcpy(lsi2->name, Config->LongName.c_str());
        strcpy(lsi2->account, Config->LoginAccount2.c_str());
        strcpy(lsi2->password, Config->LoginPassword2.c_str());
        strcpy(lsi2->address, Config->WorldAddress.c_str());
        SendPacket2(pack2);
#endif

        delete pack;

#ifdef DUAL_SERVER
        delete pack2;
#endif
}

void LoginServer::SendNewInfo() {
        uint16 port;
        const WorldConfig *Config=WorldConfig::get();

        ServerPacket* pack = new ServerPacket;
        pack->opcode = ServerOP_NewLSInfo;
        pack->size = sizeof(ServerNewLSInfo_Struct);
        pack->pBuffer = new uchar[pack->size];
        memset(pack->pBuffer, 0, pack->size);
        ServerNewLSInfo_Struct* lsi = (ServerNewLSInfo_Struct*) pack->pBuffer;
        strcpy(lsi->protocolversion, EQEMU_PROTOCOL_VERSION);
        strcpy(lsi->serverversion, CURRENT_VERSION);
        strcpy(lsi->name, Config->LongName.c_str());
        strcpy(lsi->shortname, Config->ShortName.c_str());
        strcpy(lsi->account, Config->LoginAccount.c_str());
        strcpy(lsi->password, Config->LoginPassword.c_str());
        if (Config->WorldAddress.length())
                strcpy(lsi->remote_address, Config->WorldAddress.c_str());
        if (Config->LocalAddress.length())
                strcpy(lsi->local_address, Config->LocalAddress.c_str());
        else {
                tcpc->GetSockName(lsi->local_address,&port);
                WorldConfig::SetLocalAddress(lsi->local_address);
        }
        SendPacket(pack);

#ifdef DUAL_SERVER
        ServerPacket* pack2 = new ServerPacket;
        pack2->opcode = ServerOP_NewLSInfo;
        pack2->size = sizeof(ServerNewLSInfo_Struct);
        pack2->pBuffer = new uchar[pack2->size];
        memset(pack2->pBuffer, 0, pack2->size);
        ServerNewLSInfo_Struct* lsi2 = (ServerNewLSInfo_Struct*) pack2->pBuffer;
        strcpy(lsi2->protocolversion, EQEMU_PROTOCOL_VERSION);
        strcpy(lsi2->serverversion, CURRENT_VERSION);
        strcpy(lsi2->name, Config->LongName.c_str());
        strcpy(lsi2->shortname, Config->ShortName.c_str());
        strcpy(lsi2->account, Config->LoginAccount.c_str());
        strcpy(lsi2->password, Config->LoginPassword.c_str());
        if (Config->WorldAddress.length())
                strcpy(lsi2->remote_address, Config->WorldAddress.c_str());
        if (Config->LocalAddress.length())
                strcpy(lsi2->local_address, Config->LocalAddress.c_str());
        else {
                tcpc2->GetSockName(lsi2->local_address,&port);
                WorldConfig::SetLocalAddress(lsi2->local_address);
        }
        //SendPacket(pack); Angelox
        SendPacket2(pack2);
#endif

        delete pack;

#ifdef DUAL_SERVER
        delete pack2;
#endif
}

void LoginServer::SendStatus() {
        statusupdate_timer.Start();
        ServerPacket* pack = new ServerPacket;
        pack->opcode = ServerOP_LSStatus;
        pack->size = sizeof(ServerLSStatus_Struct);
        pack->pBuffer = new uchar[pack->size];
        memset(pack->pBuffer, 0, pack->size);
        ServerLSStatus_Struct* lss = (ServerLSStatus_Struct*) pack->pBuffer;

        if (WorldConfig::get()->Locked)
                lss->status = -2;
        else if (numzones <= 0)
                lss->status = -2;
        else
                lss->status = numplayers;

        lss->num_zones = numzones;
        lss->num_players = numplayers;
        SendPacket(pack);

#ifdef DUAL_SERVER
        SendPacket2(pack);
#endif

        delete pack;
}

client.cpp
Code:

#include "../common/debug.h"
#include "../common/EQPacket.h"
#include "../common/EQStreamIntf.h"
#include "../common/misc.h"
#include <iostream>
using namespace std;
#include <iomanip>
using namespace std;
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <zlib.h>
#include <limits.h>
//FatherNitwit: uncomment to enable my IP based authentication hack
//#define IPBASED_AUTH_HACK

// Disgrace: for windows compile
#ifdef WIN32
        #include <windows.h>
        #include <winsock.h>
        #define snprintf        _snprintf
#if (_MSC_VER < 1500)
        #define vsnprintf        _vsnprintf
#endif
        #define strncasecmp        _strnicmp
        #define strcasecmp  _stricmp
#else
        #include <sys/socket.h>
#ifdef FREEBSD //Timothy Whitman - January 7, 2003
        #include <sys/types.h>
#endif
        #include <netinet/in.h>
        #include <arpa/inet.h>
        #include <unistd.h>
#endif

#include "client.h"
#include "../common/emu_opcodes.h"
#include "../common/eq_packet_structs.h"
#include "../common/packet_dump.h"
#include "../common/EQStreamIntf.h"
#include "worlddb.h"
#include "../common/Item.h"
#include "../common/races.h"
#include "../common/classes.h"
#include "../common/languages.h"
#include "../common/skills.h"
#include "../common/extprofile.h"
#include "WorldConfig.h"
#include "LoginServer.h"
#include "zoneserver.h"
#include "zonelist.h"
#include "clientlist.h"
#include "wguild_mgr.h"
#include "../common/rulesys.h"
#include "SoFCharCreateData.h"

extern ZSList zoneserver_list;
extern LoginServer loginserver;
extern ClientList client_list;
extern uint32 numclients;
extern volatile bool RunLoops;

Client::Client(EQStreamInterface* ieqs)
: autobootup_timeout(RuleI(World, ZoneAutobootTimeoutMS)),
  CLE_keepalive_timer(RuleI(World, ClientKeepaliveTimeoutMS)),
  connect(1000),
  eqs(ieqs)
{
        // Live does not send datarate as of 3/11/2005
        //eqs->SetDataRate(7);
        ip = eqs->GetRemoteIP();
        port = ntohs(eqs->GetRemotePort());

        autobootup_timeout.Disable();
        connect.Disable();
        seencharsel = false;
        cle = 0;
        zoneID = 0;
        char_name[0] = 0;
        charid = 0;
        pwaitingforbootup = 0;
        StartInTutorial = false;
        SoFClient = false;
        numclients++;
}

Client::~Client() {
        if (RunLoops && cle && zoneID == 0)
                cle->SetOnline(CLE_Status_Offline);

        numclients--;

        //let the stream factory know were done with this stream
        eqs->Close();
        eqs->ReleaseFromUse();
}

void Client::SendLogServer()
{
        EQApplicationPacket *outapp = new EQApplicationPacket(OP_LogServer, sizeof(LogServer_Struct));
        LogServer_Struct *l=(LogServer_Struct *)outapp->pBuffer;
        const char *wsn=WorldConfig::get()->ShortName.c_str();
        memcpy(l->worldshortname,wsn,strlen(wsn));

        if(RuleB(Mail, EnableMailSystem))
                l->enablemail = 1;

        if(RuleB(Chat, EnableVoiceMacros))
                l->enablevoicemacros = 1;

        if(database.GetServerType() == 1)
                l->enable_pvp = 1;

        //enable when we are ready to implement this!
        //l->enable_petition_wnd = 1;

        QueuePacket(outapp);
        safe_delete(outapp);
}

void Client::SendEnterWorld(string name)
{
char char_name[32]= { 0 };
        if (pZoning && database.GetLiveChar(GetAccountID(), char_name)) {
                if(database.GetAccountIDByChar(char_name) != GetAccountID()) {
                        eqs->Close();
                        return;
                } else {
                        clog(WORLD__CLIENT,"Telling client to continue session.");
                }
        }

        EQApplicationPacket *outapp = new EQApplicationPacket(OP_EnterWorld, strlen(char_name)+1);
        memcpy(outapp->pBuffer,char_name,strlen(char_name)+1);
        QueuePacket(outapp);
        safe_delete(outapp);
}

void Client::SendExpansionInfo() {
        EQApplicationPacket *outapp = new EQApplicationPacket(OP_ExpansionInfo, sizeof(ExpansionInfo_Struct));
        ExpansionInfo_Struct *eis = (ExpansionInfo_Struct*)outapp->pBuffer;
        char val[20] = {0};
        if (database.GetVariable("Expansions", val, 20)) {
                eis->Expansions = atoi(val);
        }
        else {
                eis->Expansions = 0x1FF;
        }
        QueuePacket(outapp);
        safe_delete(outapp);
}

void Client::SendCharInfo() {
        if (cle) {
                cle->SetOnline(CLE_Status_CharSelect);
        }

        seencharsel = true;


        // Send OP_SendCharInfo
        EQApplicationPacket *outapp = new EQApplicationPacket(OP_SendCharInfo, sizeof(CharacterSelect_Struct));
        CharacterSelect_Struct* cs = (CharacterSelect_Struct*)outapp->pBuffer;

        database.GetCharSelectInfo(GetAccountID(), cs);

        QueuePacket(outapp);
        safe_delete(outapp);
}

void Client::SendPostEnterWorld() {
        EQApplicationPacket *outapp = new EQApplicationPacket(OP_PostEnterWorld, 1);
        outapp->size=0;
        QueuePacket(outapp);
        safe_delete(outapp);
}

bool Client::HandlePacket(const EQApplicationPacket *app) {
        const WorldConfig *Config=WorldConfig::get();
        EmuOpcode opcode = app->GetOpcode();

        clog(WORLD__CLIENT_TRACE,"Recevied EQApplicationPacket");
        _pkt(WORLD__CLIENT_TRACE,app);

        bool ret = true;

        if (!eqs->CheckState(ESTABLISHED)) {
                clog(WORLD__CLIENT,"Client disconnected (net inactive on send)");
                return false;
        }

        // Voidd: Anti-GM Account hack, Checks source ip against valid GM Account IP Addresses
        if (RuleB(World, GMAccountIPList) && this->GetAdmin() >= (RuleI(World, MinGMAntiHackStatus))) {
                if(!database.CheckGMIPs(long2ip(this->GetIP()).c_str(), this->GetAccountID())) {
                        clog(WORLD__CLIENT,"GM Account not permited from source address %s and accountid %i", long2ip(this->GetIP()).c_str(), this->GetAccountID());
                        eqs->Close();
                }
        }

        if (GetAccountID() == 0 && opcode != OP_SendLoginInfo) {
                // Got a packet other than OP_SendLoginInfo when not logged in
                clog(WORLD__CLIENT_ERR,"Expecting OP_SendLoginInfo, got %s", OpcodeNames[opcode]);
                return false;
        }
        else if (opcode == OP_AckPacket) {
                return true;
        }

        switch(opcode)
        {
                case OP_CrashDump:
                        break;
                case OP_SendLoginInfo:
                {
                        if (app->size != sizeof(LoginInfo_Struct)) {
                                ret = false;
                                break;
                        }

                        string StreamDescription = eqs->Describe();

                        if(StreamDescription == "Patch SoF")
                                SoFClient = true;

                        LoginInfo_Struct *li=(LoginInfo_Struct *)app->pBuffer;

                        // Quagmire - max len for name is 18, pass 15
                        char name[19] = {0};
                        char password[16] = {0};
                        strncpy(name, (char*)li->login_info,18);
                        strncpy(password, (char*)&(li->login_info[strlen(name)+1]), 15);

                        if (strlen(password) <= 1) {
                                // TODO: Find out how to tell the client wrong username/password
                                clog(WORLD__CLIENT_ERR,"Login without a password");
                                ret = false;
                                break;
                        }

                        pZoning=(li->zoning==1);

#ifdef IPBASED_AUTH_HACK
                        struct in_addr tmpip;
                        tmpip.s_addr = ip;
#endif
                        int32 id=0;
                        bool minilogin = loginserver.MiniLogin();
                        if(minilogin){
                                struct in_addr miniip;
                                miniip.s_addr = ip;
                                id = database.GetMiniLoginAccount(inet_ntoa(miniip));
                        }
                        else if(strncasecmp(name, "LS#", 3) == 0)
                                id=atoi(&name[3]);
                        else
                                id=atoi(name);
#ifdef IPBASED_AUTH_HACK
                        if ((cle = zoneserver_list.CheckAuth(inet_ntoa(tmpip), password)))
#else

#ifdef DUAL_SERVER
                        if (loginserver.Connected() == false && !pZoning) {
                                clog(WORLD__CLIENT_ERR,"Error: You're disconnected from one login server, you need to re-connect.");
                        }
#else
                        if (loginserver.Connected() == false && !pZoning) {
                                clog(WORLD__CLIENT_ERR,"Error: Login server login while not connected to login server.");
                                ret = false;
                                break;
                        }
#endif
                        if ((minilogin && (cle = client_list.CheckAuth(id,password,ip))) || (cle = client_list.CheckAuth(id, password)))
#endif
                        {
                                if (cle->AccountID() == 0 || (!minilogin && cle->LSID()==0)) {
                                        clog(WORLD__CLIENT_ERR,"ID is 0.  Is this server connected to minilogin?");
                                        if(!minilogin)
                                                clog(WORLD__CLIENT_ERR,"If so you forget the minilogin variable...");
                                        else
                                                clog(WORLD__CLIENT_ERR,"Could not find a minilogin account, verify ip address logging into minilogin is the same that is in your account table.");
                                        ret = false;
                                        break;
                                }

                                cle->SetOnline();

                                clog(WORLD__CLIENT,"Logged in. Mode=%s",pZoning ? "(Zoning)" : "(CharSel)");

                                if(minilogin){
                                        WorldConfig::DisableStats();
                                        clog(WORLD__CLIENT,"MiniLogin Account #%d",cle->AccountID());
                                }
                                else {
                                        clog(WORLD__CLIENT,"LS Account #%d",cle->LSID());
                                }
                                if(Config->UpdateStats){
                                        ServerPacket* pack = new ServerPacket;
                                        pack->opcode = ServerOP_LSPlayerJoinWorld;
                                        pack->size = sizeof(ServerLSPlayerJoinWorld_Struct);
                                        pack->pBuffer = new uchar[pack->size];
                                        memset(pack->pBuffer,0,pack->size);
                                        ServerLSPlayerJoinWorld_Struct* join =(ServerLSPlayerJoinWorld_Struct*)pack->pBuffer;
                                        strcpy(join->key,GetLSKey());
                                        join->lsaccount_id = GetLSID();
                                        loginserver.SendPacket(pack);
#ifdef DUAL_SERVER
                                        loginserver.SendPacket2(pack);
#endif
                                        safe_delete(pack);
                                }

                                if (!pZoning)
                                        SendGuildList();
                                SendLogServer();
                                SendApproveWorld();
                                SendEnterWorld(cle->name());
                                SendPostEnterWorld();
                                if (!pZoning) {
                                        SendExpansionInfo();
                                        SendCharInfo();
                                        database.LoginIP(cle->AccountID(), long2ip(GetIP()).c_str());
                                }
                        }
                        else {
                                // TODO: Find out how to tell the client wrong username/password
                                clog(WORLD__CLIENT_ERR,"Bad/Expired session key '%s'",name);
                                ret = false;
                                break;
                        }

                        if (!cle)
                                break;
                        cle->SetIP(GetIP());
                        break;
                }
                case OP_ApproveName: //Name approval
                {
                        if (GetAccountID() == 0) {
                                clog(WORLD__CLIENT_ERR,"Name approval request with no logged in account");
                                ret = false;
                                break;
                        }
                        snprintf(char_name, 64, "%s", (char*)app->pBuffer);
                        uchar race = app->pBuffer[64];
                        uchar clas = app->pBuffer[68];

                        clog(WORLD__CLIENT,"Name approval request.  Name=%s, race=%s, class=%s",char_name,GetRaceName(race),GetEQClassName(clas));

                        EQApplicationPacket *outapp;
                        outapp = new EQApplicationPacket;
                        outapp->SetOpcode(OP_ApproveName);
                        outapp->pBuffer = new uchar[1];
                        outapp->size = 1;
                        bool valid;
                        if(!database.CheckNameFilter(char_name)) {
                                valid = false;
                        }
                        else if(char_name[0] < 'A' && char_name[0] > 'Z') {
                                //name must begin with an upper-case letter.
                                valid = false;
                        }
                        else if (database.ReserveName(GetAccountID(), char_name)) {
                                valid = true;
                        }
                        else {
                                valid = false;
                        }
                        outapp->pBuffer[0] = valid? 1 : 0;
                        QueuePacket(outapp);
                        safe_delete(outapp);
                        break;
                }
                case OP_RandomNameGenerator:
                {
                        // creates up to a 10 char name
                        char vowels[18]="aeiouyaeiouaeioe";
                        char cons[48]="bcdfghjklmnpqrstvwxzybcdgklmnprstvwbcdgkpstrkd";
                        char rndname[17]="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
                        char paircons[33]="ngrkndstshthphsktrdrbrgrfrclcr";
                        int rndnum=rand()%76,n=1;
                        bool dlc=false;
                        bool vwl=false;
                        bool dbl=false;
                        if (rndnum>63)
                        {        // rndnum is 0 - 75 where 64-75 is cons pair, 17-63 is cons, 0-16 is vowel
                                rndnum=(rndnum-61)*2;        // name can't start with "ng" "nd" or "rk"
                                rndname[0]=paircons[rndnum];
                                rndname[1]=paircons[rndnum+1];
                                n=2;
                        }
                        else if (rndnum>16)
                        {
                                rndnum-=17;
                                rndname[0]=cons[rndnum];
                        }
                        else
                        {
                                rndname[0]=vowels[rndnum];
                                vwl=true;
                        }
                        int namlen=(rand()%6)+5;
                        for (int i=n;i<namlen;i++)
                        {
                                dlc=false;
                                if (vwl)        //last char was a vowel
                                {                        // so pick a cons or cons pair
                                        rndnum=rand()%63;
                                        if (rndnum>46)
                                        {        // pick a cons pair
                                                if (i>namlen-3)        // last 2 chars in name?
                                                {        // name can only end in cons pair "rk" "st" "sh" "th" "ph" "sk" "nd" or "ng"
                                                        rndnum=(rand()%8)*2;
                                                }
                                                else
                                                {        // pick any from the set
                                                        rndnum=(rndnum-47)*2;
                                                }
                                                rndname[i]=paircons[rndnum];
                                                rndname[i+1]=paircons[rndnum+1];
                                                dlc=true;        // flag keeps second letter from being doubled below
                                                i+=1;
                                        }
                                        else
                                        {        // select a single cons
                                                rndname[i]=cons[rndnum];
                                        }
                                }
                                else
                                {                // select a vowel
                                        rndname[i]=vowels[rand()%17];
                                }
                                vwl=!vwl;
                                if (!dbl && !dlc)
                                {        // one chance at double letters in name
                                        if (!(rand()%(i+10)))        // chances decrease towards end of name
                                        {
                                                rndname[i+1]=rndname[i];
                                                dbl=true;
                                                i+=1;
                                        }
                                }
                        }

                        rndname[0]=toupper(rndname[0]);
                        NameGeneration_Struct* ngs = (NameGeneration_Struct*)app->pBuffer;
                        memset(ngs->name,0,64);
                        strcpy(ngs->name,rndname);

//                        char names[8][64] = { "How", "About", "You", "Think", "Of", "Your", "Own", "Name" };
//                        //Could have parts of the random name in this struct and they compile together
//                        NameGeneration_Struct* ngs = (NameGeneration_Struct*)app->pBuffer;
//                        strncpy(ngs->name,"Notcreated",64);

                        QueuePacket(app);
                        break;

                }
                case OP_CharacterCreateRequest: {
                        // New OpCode in SoF
                        //
                        SoFClient = true;
                        EQApplicationPacket *outapp = new EQApplicationPacket(OP_CharacterCreateRequest, sizeof(SoFCharCreateInfo));
                        memcpy(outapp->pBuffer, &SoFCharCreateInfo, sizeof(SoFCharCreateInfo));
                        QueuePacket(outapp);
                        safe_delete(outapp);
                        break;
                }

                case OP_CharacterCreate: //Char create
                {
                        if (GetAccountID() == 0)
                        {
                                clog(WORLD__CLIENT_ERR,"Account ID not set; unable to create character.");
                                ret = false;
                                break;
                        }
                        else if (app->size != sizeof(CharCreate_Struct))
                        {
                                clog(WORLD__CLIENT_ERR,"Wrong size on OP_CharacterCreate. Got: %d, Expected: %d",app->size,sizeof(CharCreate_Struct));
                                DumpPacket(app);
                                break;
                        }

                        CharCreate_Struct *cc = (CharCreate_Struct*)app->pBuffer;
                        if(OPCharCreate(char_name,cc) == false)
                        {
                                database.DeleteCharacter(char_name);
                                EQApplicationPacket *outapp = new EQApplicationPacket(OP_ApproveName, 1);
                                outapp->pBuffer[0] = 0;
                                QueuePacket(outapp);
                                safe_delete(outapp);
                        }
                  else
                        StartInTutorial = true;
                        SendCharInfo();

                        break;
                }
                case OP_EnterWorld: // Enter world
                {
                        if (GetAccountID() == 0) {
                                clog(WORLD__CLIENT_ERR,"Enter world with no logged in account");
                                eqs->Close();
                                break;
                        }
                        if(GetAdmin() < 0)
                        {
                                clog(WORLD__CLIENT,"Account banned or suspended.");
                                eqs->Close();
                                break;
                        }

                        if (RuleI(World, MaxClientsPerIP) >= 0) {
                    client_list.GetCLEIP(this->GetIP());  //Lieka Edit Begin:  Check current CLE Entry IPs against incoming connection
            }

                        EnterWorld_Struct *ew=(EnterWorld_Struct *)app->pBuffer;
                        strncpy(char_name, ew->name, 64);

                        EQApplicationPacket *outapp;
                        int32 tmpaccid = 0;
                        charid = database.GetCharacterInfo(char_name, &tmpaccid, &zoneID, &instanceID);
                        if (charid == 0 || tmpaccid != GetAccountID()) {
                                clog(WORLD__CLIENT_ERR,"Could not get CharInfo for '%s'",char_name);
                                eqs->Close();
                                break;
                        }

                        // Make sure this account owns this character
                        if (tmpaccid != GetAccountID()) {
                                clog(WORLD__CLIENT_ERR,"This account does not own the character named '%s'",char_name);
                                eqs->Close();
                                break;
                        }

                        if(!pZoning && ew->return_home)
                        {
                                CharacterSelect_Struct* cs = new CharacterSelect_Struct;
                                memset(cs, 0, sizeof(CharacterSelect_Struct));
                                database.GetCharSelectInfo(GetAccountID(), cs);
                                bool home_enabled = false;

                                for(int x = 0; x < 10; ++x)
                                {
                                        if(strcasecmp(cs->name[x], char_name) == 0)
                                        {
                                                if(cs->gohome[x] == 1)
                                                {
                                                        home_enabled = true;
                                                        break;
                                                }
                                        }
                                }
                                safe_delete(cs);

                                if(home_enabled)
                                {
                                        zoneID = database.MoveCharacterToBind(charid,4);
                                }
                                else
                                {
                                        clog(WORLD__CLIENT_ERR,"'%s' is trying to go home before they're able...",char_name);
                                        database.SetHackerFlag(GetAccountName(), char_name, "MQGoHome: player tried to enter the tutorial without having go home enabled for this character.");
                                        eqs->Close();
                                        break;
                                }
                        }
/*
                        if(!pZoning && (RuleB(World, EnableTutorialButton) && (ew->tutorial || StartInTutorial))) {
                                CharacterSelect_Struct* cs = new CharacterSelect_Struct;
                                memset(cs, 0, sizeof(CharacterSelect_Struct));
                                database.GetCharSelectInfo(GetAccountID(), cs);
                                bool tutorial_enabled = false;

                                for(int x = 0; x < 10; ++x)
                                {
                                        if(strcasecmp(cs->name[x], char_name) == 0)
                                        {
                                                if(cs->tutorial[x] == 1)
                                                {
                                                        tutorial_enabled = true;
                                                        break;
                                                }
                                        }
                                }
                                safe_delete(cs);

                                if(tutorial_enabled)
                                {
                                        zoneID = RuleI(World, TutorialZoneID);
                                        database.MoveCharacterToZone(charid, database.GetZoneName(zoneID));
                                }
                                else
                                {
                                        clog(WORLD__CLIENT_ERR,"'%s' is trying to go to tutorial but are not allowed...",char_name);
                                        database.SetHackerFlag(GetAccountName(), char_name, "MQTutorial: player tried to enter the tutorial without having tutorial enabled for this character.");
                                        eqs->Close();
                                        break;
                                }

                                // HACK: Entering the Tutorial directly from Character Creation (without going back to Char Select)
                                // does not work correctly yet in SoF, so bounce them back to Character Select first.
                                //
                                if(SoFClient && StartInTutorial) {
                                        ZoneUnavail();
                                        StartInTutorial = false;
                                        break;
                                }
                        }
*/
                        if (zoneID == 0 || !database.GetZoneName(zoneID)) {
                                // This is to save people in an invalid zone, once it's removed from the DB
                                database.MoveCharacterToZone(charid, "arena");
                                clog(WORLD__CLIENT_ERR, "Zone not found in database zone_id=%i, moveing char to arena character:%s", zoneID, char_name);
                        }

                        if(instanceID > 0)
                        {
                                if(!database.VerifyInstanceAlive(instanceID, GetCharID()))
                                {
                                        zoneID = database.MoveCharacterToBind(charid);
                                        instanceID = 0;
                                }
                                else
                                {
                                        if(!database.VerifyZoneInstance(zoneID, instanceID))
                                        {
                                                zoneID = database.MoveCharacterToBind(charid);
                                                instanceID = 0;
                                        }
                                }
                        }

                        if(!pZoning) {
                                database.SetGroupID(char_name, 0, charid);
                                database.SetLFP(charid, false);
                                database.SetLFG(charid, false);
                        }
                        else{
                                int32 groupid=database.GetGroupID(char_name);
                                if(groupid>0){
                                        char* leader=0;
                                        char leaderbuf[64]={0};
                                        if((leader=database.GetGroupLeaderForLogin(char_name,leaderbuf)) && strlen(leader)>1){
                                                EQApplicationPacket* outapp3 = new EQApplicationPacket(OP_GroupUpdate,sizeof(GroupJoin_Struct));
                                                GroupJoin_Struct* gj=(GroupJoin_Struct*)outapp3->pBuffer;
                                                gj->action=8;
                                                strcpy(gj->yourname,char_name);
                                                strcpy(gj->membername,leader);
                                                QueuePacket(outapp3);
                                                safe_delete(outapp3);
                                        }
                                }
                        }
//Angelox
                        outapp = new EQApplicationPacket(OP_MOTD);

#ifdef DUAL_SERVER
                        char tmp[500] = {0};
                        if ((database.GetVariable("MOTD", tmp, 500)) && (GetLSID() > 4999999)) {
                                outapp->size = strlen(tmp)+1;
                                outapp->pBuffer = new uchar[outapp->size];
                                memset(outapp->pBuffer,0,outapp->size);
                                strcpy((char*)outapp->pBuffer, tmp);
                        }
                        else if ((database.GetVariable("MOTDEqEmu", tmp, 500)) && (GetLSID() < 5000000)) {
                                outapp->size = strlen(tmp)+1;
                                outapp->pBuffer = new uchar[outapp->size];
                                memset(outapp->pBuffer,0,outapp->size);
                                strcpy((char*)outapp->pBuffer, tmp);
                        }
#else
                        char tmp[500] = {0};
                        if (database.GetVariable("MOTD", tmp, 500)) {
                                outapp->size = strlen(tmp)+1;
                                outapp->pBuffer = new uchar[outapp->size];
                                memset(outapp->pBuffer,0,outapp->size);
                                strcpy((char*)outapp->pBuffer, tmp);
                        }
#endif

                        else {
                                // Null Message of the Day. :)
                                outapp->size = 1;
                                outapp->pBuffer = new uchar[outapp->size];
                                outapp->pBuffer[0] = 0;
                        }
                        QueuePacket(outapp);
                        safe_delete(outapp);

                        int MailKey = MakeRandomInt(1, INT_MAX);

                        database.SetMailKey(charid, GetIP(), MailKey);

                        char ConnectionType = (SoFClient ? 'S' : 'C');

                        EQApplicationPacket *outapp2 = new EQApplicationPacket(OP_SetChatServer);
                        char buffer[112];
                        sprintf(buffer,"%s,%i,%s.%s,%c%08X",
                                Config->ChatHost.c_str(),
                                Config->ChatPort,
                                Config->ShortName.c_str(),
                                this->GetCharName(), ConnectionType, MailKey
                        );
                        outapp2->size=strlen(buffer)+1;
                        outapp2->pBuffer = new uchar[outapp2->size];
                        memcpy(outapp2->pBuffer,buffer,outapp2->size);
                        QueuePacket(outapp2);
                        safe_delete(outapp2);

                        outapp2 = new EQApplicationPacket(OP_SetChatServer2);

                        if(!SoFClient)
                                ConnectionType = 'M';

                        sprintf(buffer,"%s,%i,%s.%s,%c%08X",
                                Config->MailHost.c_str(),
                                Config->MailPort,
                                Config->ShortName.c_str(),
                                this->GetCharName(), ConnectionType, MailKey
                        );
                        outapp2->size=strlen(buffer)+1;
                        outapp2->pBuffer = new uchar[outapp2->size];
                        memcpy(outapp2->pBuffer,buffer,outapp2->size);
                        QueuePacket(outapp2);
                        safe_delete(outapp2);

                        EnterWorld();
                        break;
                }
                case OP_LoginComplete:{
                        break;
                }
                case OP_DeleteCharacter: {
                        int32 char_acct_id = database.GetAccountIDByChar((char*)app->pBuffer);
                        if(char_acct_id == GetAccountID())
                        {
                        clog(WORLD__CLIENT,"Delete character: %s",app->pBuffer);
                        database.DeleteCharacter((char *)app->pBuffer);
                        SendCharInfo();
                        }
                        break;
                }
                case OP_ApproveWorld:
                {
                        break;
                }
                case OP_WorldClientReady:{
                        break;
                }
                case OP_World_Client_CRC1:
                case OP_World_Client_CRC2: {
                        // Derision: There is no obvious entry in the CC struct to indicate that the 'Start Tutorial button
                        // is selected when a character is created. I have observed that in this case, OP_EnterWorld is sent
                        // before OP_World_Client_CRC1. Therefore, if we receive OP_World_Client_CRC1 before OP_EnterWorld,
                        // then 'Start Tutorial' was not chosen.
                        StartInTutorial = false;
                        break;
                }
                case OP_WearChange: { // User has selected a different character
                        break;
                }
                case OP_WorldComplete: {
                        eqs->Close();
                        break;
                }
                case OP_LoginUnknown1:
                case OP_LoginUnknown2:
                        break;

                default: {
                        clog(WORLD__CLIENT_ERR,"Received unknown EQApplicationPacket");
                        _pkt(WORLD__CLIENT_ERR,app);
                        break;
                }
        }
        return ret;
}

bool Client::Process() {
        bool ret = true;
        //bool sendguilds = true;
    sockaddr_in to;

        memset((char *) &to, 0, sizeof(to));
    to.sin_family = AF_INET;
    to.sin_port = port;
    to.sin_addr.s_addr = ip;

        if (autobootup_timeout.Check()) {
                clog(WORLD__CLIENT_ERR, "Zone bootup timer expired, bootup failed or too slow.");
                ZoneUnavail();
        }
        if(connect.Check()){
                SendGuildList();// Send OPCode: OP_GuildsList
                SendApproveWorld();
                connect.Disable();
        }
        if (CLE_keepalive_timer.Check()) {
                if (cle)
                        cle->KeepAlive();
        }

        /************ Get all packets from packet manager out queue and process them ************/
        EQApplicationPacket *app = 0;
        while(ret && (app = (EQApplicationPacket *)eqs->PopPacket())) {
                ret = HandlePacket(app);

                delete app;
        }

        if (!eqs->CheckState(ESTABLISHED)) {
                if(WorldConfig::get()->UpdateStats){
                        ServerPacket* pack = new ServerPacket;
                        pack->opcode = ServerOP_LSPlayerLeftWorld;
                        pack->size = sizeof(ServerLSPlayerLeftWorld_Struct);
                        pack->pBuffer = new uchar[pack->size];
                        memset(pack->pBuffer,0,pack->size);
                        ServerLSPlayerLeftWorld_Struct* logout =(ServerLSPlayerLeftWorld_Struct*)pack->pBuffer;
                        strcpy(logout->key,GetLSKey());
                        logout->lsaccount_id = GetLSID();
                        loginserver.SendPacket(pack);
#ifdef DUAL_SERVER
                        loginserver.SendPacket2(pack);
#endif
                        safe_delete(pack);
                }
                clog(WORLD__CLIENT,"Client disconnected (not active in process)");
                return false;
        }

        return ret;
}

void Client::EnterWorld(bool TryBootup) {
        if (zoneID == 0)
                return;

        ZoneServer* zs = NULL;
        if(instanceID > 0)
        {
                if(database.VerifyInstanceAlive(instanceID, GetCharID()))
                {
                        if(database.VerifyZoneInstance(zoneID, instanceID))
                        {
                                zs = zoneserver_list.FindByInstanceID(instanceID);
                        }
                        else
                        {
                                instanceID = 0;
                                zs = NULL;
                                database.MoveCharacterToBind(GetCharID());
                                ZoneUnavail();
                                return;
                        }
                }
                else
                {
                        instanceID = 0;
                        zs = NULL;
                        database.MoveCharacterToBind(GetCharID());
                        ZoneUnavail();
                        return;
                }
        }
        else
                zs = zoneserver_list.FindByZoneID(zoneID);


        const char *zone_name=database.GetZoneName(zoneID, true);
        if (zs) {
                // warn the world we're comming, so it knows not to shutdown
                zs->IncommingClient(this);
        }
        else {
                if (TryBootup) {
                        clog(WORLD__CLIENT,"Attempting autobootup of %s (%d:%d)",zone_name,zoneID,instanceID);
                        autobootup_timeout.Start();
                        pwaitingforbootup = zoneserver_list.TriggerBootup(zoneID, instanceID);
                        if (pwaitingforbootup == 0) {
                                clog(WORLD__CLIENT_ERR,"No zoneserver available to boot up.");
                                ZoneUnavail();
                        }
                        return;
                }
                else {
                        clog(WORLD__CLIENT_ERR,"Requested zone %s is no running.",zone_name);
                        ZoneUnavail();
                        return;
                }
        }
        pwaitingforbootup = 0;

        cle->SetChar(charid, char_name);
        database.UpdateLiveChar(char_name, GetAccountID());
        clog(WORLD__CLIENT,"%s %s (%d:%d)",seencharsel ? "Entering zone" : "Zoning to",zone_name,zoneID,instanceID);
//        database.SetAuthentication(account_id, char_name, zone_name, ip);

        if (seencharsel) {
                if (GetAdmin() < 80 && zoneserver_list.IsZoneLocked(zoneID)) {
                        clog(WORLD__CLIENT_ERR,"Enter world failed.  Zone is locked.");
                        ZoneUnavail();
                        return;
                }

                ServerPacket* pack = new ServerPacket;
                pack->opcode = ServerOP_AcceptWorldEntrance;
                pack->size = sizeof(WorldToZone_Struct);
                pack->pBuffer = new uchar[pack->size];
                memset(pack->pBuffer, 0, pack->size);
                WorldToZone_Struct* wtz = (WorldToZone_Struct*) pack->pBuffer;
                wtz->account_id = GetAccountID();
                wtz->response = 0;
                zs->SendPacket(pack);
                delete pack;
        }
        else {        // if they havent seen character select screen, we can assume this is a zone
                        // to zone movement, which should be preauthorized before they leave the previous zone
                Clearance(1);
        }
}

void Client::Clearance(sint8 response)
{
        ZoneServer* zs = NULL;
        if(instanceID > 0)
        {
                zs = zoneserver_list.FindByInstanceID(instanceID);
        }
        else
        {
                zs = zoneserver_list.FindByZoneID(zoneID);
        }

    if(zs == 0 || response == -1 || response == 0)
    {
        if (zs == 0)
        {
            clog(WORLD__CLIENT_ERR,"Unable to find zoneserver in Client::Clearance!!");
        } else {
                clog(WORLD__CLIENT_ERR, "Invalid response %d in Client::Clearance", response);
        }

        ZoneUnavail();
        return;
    }

        EQApplicationPacket* outapp;

    if (zs->GetCAddress() == NULL) {
        clog(WORLD__CLIENT_ERR, "Unable to do zs->GetCAddress() in Client::Clearance!!");
        ZoneUnavail();
        return;
    }

    if (zoneID == 0) {
        clog(WORLD__CLIENT_ERR, "zoneID is NULL in Client::Clearance!!");
        ZoneUnavail();
        return;
    }

        const char* zonename = database.GetZoneName(zoneID);
    if (zonename == 0) {
        clog(WORLD__CLIENT_ERR, "zonename is NULL in Client::Clearance!!");
        ZoneUnavail();
        return;
    }

        // @bp This is the chat server
        /*
        char packetData[] = "64.37.148.34.9876,MyServer,Testchar,23cd2c95";
        outapp = new EQApplicationPacket(OP_0x0282, sizeof(packetData));
        strcpy((char*)outapp->pBuffer, packetData);
        QueuePacket(outapp);
        delete outapp;
        */

        // Send zone server IP data
        outapp = new EQApplicationPacket(OP_ZoneServerInfo, sizeof(ZoneServerInfo_Struct));
        ZoneServerInfo_Struct* zsi = (ZoneServerInfo_Struct*)outapp->pBuffer;
        const char *zs_addr=zs->GetCAddress();
        if (!zs_addr[0]) {
                if (cle->IsLocalClient()) {
                        struct in_addr  in;
                        in.s_addr = zs->GetIP();
                        zs_addr=inet_ntoa(in);
                        if (!strcmp(zs_addr,"127.0.0.1"))
                                zs_addr=WorldConfig::get()->LocalAddress.c_str();
                } else {
                        zs_addr=WorldConfig::get()->WorldAddress.c_str();
                }
        }
        strcpy(zsi->ip, zs_addr);
        zsi->port =zs->GetCPort();
        clog(WORLD__CLIENT,"Sending client to zone %s (%d:%d) at %s:%d",zonename,zoneID,instanceID,zsi->ip,zsi->port);
        QueuePacket(outapp);
        safe_delete(outapp);

        if (cle)
                cle->SetOnline(CLE_Status_Zoning);
}

void Client::ZoneUnavail() {
        EQApplicationPacket* outapp = new EQApplicationPacket(OP_ZoneUnavail, sizeof(ZoneUnavail_Struct));
        ZoneUnavail_Struct* ua = (ZoneUnavail_Struct*)outapp->pBuffer;
        const char* zonename = database.GetZoneName(zoneID);
        if (zonename)
                strcpy(ua->zonename, zonename);
        QueuePacket(outapp);
        delete outapp;

        zoneID = 0;
        pwaitingforbootup = 0;
        autobootup_timeout.Disable();
}

bool Client::GenPassKey(char* key) {
        char* passKey=NULL;
        *passKey += ((char)('A'+((int)(rand()%26))));
        *passKey += ((char)('A'+((int)(rand()%26))));
        memcpy(key, passKey, strlen(passKey));
        return true;
}

void Client::QueuePacket(const EQApplicationPacket* app, bool ack_req) {
        clog(WORLD__CLIENT_TRACE, "Sending EQApplicationPacket OpCode 0x%04x",app->GetOpcode());
        _pkt(WORLD__CLIENT_TRACE, app);

        ack_req = true;        // It's broke right now, dont delete this line till fix it. =P
        eqs->QueuePacket(app, ack_req);
}

void Client::SendGuildList() {
        EQApplicationPacket *outapp;
        outapp = new EQApplicationPacket(OP_GuildsList);

        //ask the guild manager to build us a nice guild list packet
        outapp->pBuffer = guild_mgr.MakeGuildList("", outapp->size);
        if(outapp->pBuffer == NULL) {
                clog(GUILDS__ERROR, "Unable to make guild list!");
                return;
        }

        clog(GUILDS__OUT_PACKETS, "Sending OP_GuildsList of length %d", outapp->size);
//        _pkt(GUILDS__OUT_PACKET_TRACE, outapp);

        eqs->FastQueuePacket((EQApplicationPacket **)&outapp);
}

// @merth: I have no idea what this struct is for, so it's hardcoded for now
void Client::SendApproveWorld()
{
        EQApplicationPacket* outapp;

        // Send OPCode: OP_ApproveWorld, size: 544
        outapp = new EQApplicationPacket(OP_ApproveWorld, sizeof(ApproveWorld_Struct));
        ApproveWorld_Struct* aw = (ApproveWorld_Struct*)outapp->pBuffer;
        uchar foo[] = {
//0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x95,0x5E,0x30,0xA5,0xCA,0xD4,0xEA,0xF5,
//0xCB,0x14,0xFC,0xF7,0x78,0xE2,0x73,0x15,0x90,0x17,0xCE,0x7A,0xEB,0xEC,0x3C,0x34,
//0x5C,0x6D,0x10,0x05,0xFC,0xEA,0xED,0x19,0xC5,0x0D,0x7A,0x82,0x17,0xCC,0xCC,0x71,
//0x56,0x38,0xDF,0x78,0x8D,0xE6,0x44,0xD3,0x6F,0xDB,0xE3,0xCF,0x21,0x30,0x75,0x2F,
//0xCD,0xDC,0xE9,0xB4,0xA4,0x4E,0x58,0xDE,0xEE,0x54,0xDD,0x87,0xDA,0xE9,0xC6,0xC8,
//0x02,0xDD,0xC4,0xFD,0x94,0x36,0x32,0xAD,0x1B,0x39,0x0F,0x00,0x00,0x00,0x00,0x00,

0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x37,0x87,0x13,0xbe,0xc8,0xa7,0x77,0xcb,
0x27,0xed,0xe1,0xe6,0x5d,0x1c,0xaa,0xd3,0x3c,0x26,0x3b,0x6d,0x8c,0xdb,0x36,0x8d,
0x91,0x72,0xf5,0xbb,0xe0,0x5c,0x50,0x6f,0x09,0x6d,0xc9,0x1e,0xe7,0x2e,0xf4,0x38,
0x1b,0x5e,0xa8,0xc2,0xfe,0xb4,0x18,0x4a,0xf7,0x72,0x85,0x13,0xf5,0x63,0x6c,0x16,
0x69,0xf4,0xe0,0x17,0xff,0x87,0x11,0xf3,0x2b,0xb7,0x73,0x04,0x37,0xca,0xd5,0x77,
0xf8,0x03,0x20,0x0a,0x56,0x8b,0xfb,0x35,0xff,0x59,0x00,0x00,0x00,0x00,0x00,0x00,

//0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1f,0x42,0x69,0x2a,0x87,0xdd,0x04,0x3d,
//0x7f,0xb1,0xb3,0xbb,0xde,0xd5,0x5f,0xfc,0x1f,0xb3,0x25,0x94,0x16,0xd5,0xf3,0x97,
//0x43,0xdf,0xb9,0x69,0x68,0xdf,0x2b,0x64,0x98,0xf5,0x44,0xbe,0x38,0x65,0xef,0xff,
//0x36,0x89,0x90,0xcf,0x26,0xbb,0x9f,0x76,0xd5,0xaf,0x6d,0xf2,0x08,0xbe,0xce,0xd8,
//0x3e,0x4b,0x53,0x8a,0xf3,0x44,0x7c,0x19,0x49,0x5d,0x97,0x99,0xd8,0x8b,0xee,0x10,
//0x1a,0x7d,0xb7,0x8b,0x49,0x9b,0x40,0x8c,0xea,0x49,0x09,0x00,0x00,0x00,0x00,0x00,
//
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x53,0xC3,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00
};
        memcpy(aw->unknown544, foo, sizeof(foo));
        QueuePacket(outapp);
        safe_delete(outapp);
}

bool Client::OPCharCreate(char *name, CharCreate_Struct *cc)
{
        PlayerProfile_Struct pp;
        ExtendedProfile_Struct ext;
        Inventory inv;
        time_t bday = time(NULL);
        char startzone[50]={0};
        uint32 i;
        struct in_addr        in;


        int stats_sum = cc->STR + cc->STA + cc->AGI + cc->DEX +
                cc->WIS + cc->INT + cc->CHA;

        in.s_addr = GetIP();
        clog(WORLD__CLIENT,"Character creation request from %s LS#%d (%s:%d) : ", GetCLE()->LSName(), GetCLE()->LSID(), inet_ntoa(in), GetPort());
        clog(WORLD__CLIENT,"Name: %s", name);
        clog(WORLD__CLIENT,"Race: %d  Class: %d  Gender: %d  Deity: %d  Start zone: %d",
                cc->race, cc->class_, cc->gender, cc->deity, cc->start_zone);
        clog(WORLD__CLIENT,"STR  STA  AGI  DEX  WIS  INT  CHA    Total");
        clog(WORLD__CLIENT,"%3d  %3d  %3d  %3d  %3d  %3d  %3d    %3d",
                cc->STR, cc->STA, cc->AGI, cc->DEX, cc->WIS, cc->INT, cc->CHA,
                stats_sum);
        clog(WORLD__CLIENT,"Face: %d  Eye colors: %d %d", cc->face, cc->eyecolor1, cc->eyecolor2);
        clog(WORLD__CLIENT,"Hairstyle: %d  Haircolor: %d", cc->hairstyle, cc->haircolor);
        clog(WORLD__CLIENT,"Beard: %d  Beardcolor: %d", cc->beard, cc->beardcolor);

        // validate the char creation struct
        if(!CheckCharCreateInfo(cc))
        {
                clog(WORLD__CLIENT_ERR,"CheckCharCreateInfo did not validate the request (bad race/class/stats)");
                return false;
        }

        // Convert incoming cc_s to the new PlayerProfile_Struct
        memset(&pp, 0, sizeof(PlayerProfile_Struct));        // start building the profile

        InitExtendedProfile(&ext);

        strncpy(pp.name, name, 63);
        // clean the capitalization of the name
#if 0        // on second thought, don't - this will just make the creation fail
// because the name won't match what was already reserved earlier
        for (i = 0; pp.name[i] && i < 63; i++)
        {
                if(!isalpha(pp.name[i]))
                        return false;
                pp.name[i] = tolower(pp.name[i]);
        }
        pp.name[0] = toupper(pp.name[0]);
#endif

        pp.race                                = cc->race;
        pp.class_                        = cc->class_;
        pp.gender                        = cc->gender;
        pp.deity                        = cc->deity;
        pp.STR                                = cc->STR;
        pp.STA                                = cc->STA;
        pp.AGI                                = cc->AGI;
        pp.DEX                                = cc->DEX;
        pp.WIS                                = cc->WIS;
        pp.INT                                = cc->INT;
        pp.CHA                                = cc->CHA;
        pp.face                                = cc->face;
        pp.eyecolor1                = cc->eyecolor1;
        pp.eyecolor2                = cc->eyecolor2;
        pp.hairstyle                = cc->hairstyle;
        pp.haircolor                = cc->haircolor;
        pp.beard                        = cc->beard;
        pp.beardcolor                = cc->beardcolor;
        pp.drakkin_heritage                = cc->drakkin_heritage;
        pp.drakkin_tattoo                = cc->drakkin_tattoo;
        pp.drakkin_details                = cc->drakkin_details;
        pp.birthday                = bday;
        pp.lastlogin        = bday;
        pp.level                        = 1;
        pp.points                        = 5;
        pp.cur_hp                        = 1000; // 1k hp during dev only
        //what was the point of this? zone dosent handle this:
        //pp.expAA                        = 0xFFFFFFFF;

        pp.hunger_level = 6000;
        pp.thirst_level = 6000;


        // FIXME: FV roleplay, database goodness...

        // Racial Languages
        SetRacialLanguages( &pp ); // bUsh
        SetRaceStartingSkills( &pp ); // bUsh
        SetClassStartingSkills( &pp ); // bUsh
        pp.skills[SENSE_HEADING] = 200;
        // Some one fucking fix this to use a field name. -Doodman
        //pp.unknown3596[28] = 15; // @bp: This is to enable disc usage
//        strcpy(pp.servername, WorldConfig::get()->ShortName.c_str());


        for(i = 0; i < MAX_PP_SPELLBOOK; i++)
                pp.spell_book[i] = 0xFFFFFFFF;

        for(i = 0; i < MAX_PP_MEMSPELL; i++)
                pp.mem_spells[i] = 0xFFFFFFFF;

        for(i = 0; i < BUFF_COUNT; i++)
                pp.buffs[i].spellid = 0xFFFF;


        //was memset(pp.unknown3704, 0xffffffff, 8);
        //but I dont think thats what you really wanted to do...
        //memset is byte based

        //If server is PVP by default, make all character set to it.
        pp.pvp = database.GetServerType() == 1 ? 1 : 0;

        //If it is an SoF Client and the SoF Start Zone rule is set, send new chars there
        if(SoFClient && (RuleI(World, SoFStartZoneID) > 0)) {
                clog(WORLD__CLIENT,"Found 'SoFStartZoneID' rule setting: %i", (RuleI(World, SoFStartZoneID)));
                pp.zone_id = (RuleI(World, SoFStartZoneID));
                if(pp.zone_id)
                        database.GetSafePoints(pp.zone_id, &pp.x, &pp.y, &pp.z);
                else
                        clog(WORLD__CLIENT_ERR,"Error getting zone id for Zone ID %i", (RuleI(World, SoFStartZoneID)));
        }
        else
        {
                // if there's a startzone variable put them in there
                if(database.GetVariable("startzone", startzone, 50))
                {
                        clog(WORLD__CLIENT,"Found 'startzone' variable setting: %s", startzone);
                        pp.zone_id = database.GetZoneID(startzone);
                        if(pp.zone_id)
                                database.GetSafePoints(pp.zone_id, &pp.x, &pp.y, &pp.z);
                        else
                                clog(WORLD__CLIENT_ERR,"Error getting zone id for '%s'", startzone);
                }
                else  // otherwise use normal starting zone logic
                {
                        if(!SoFClient)
                                database.GetStartZone(&pp, cc);
                        else
                                database.GetStartZoneSoF(&pp, cc);
                }
        }

        if(!pp.zone_id)
        {
                pp.zone_id = 1;                // qeynos
                pp.x = pp.y = pp.z = -1;
        }

        if(!pp.binds[0].zoneId)
        {
                pp.binds[0].zoneId = pp.zone_id;
                pp.binds[0].x = pp.x;
                pp.binds[0].y = pp.y;
                pp.binds[0].z = pp.z;
                pp.binds[0].heading = pp.heading;
        }

        // set starting city location to the initial bind point
        pp.binds[4] = pp.binds[0];


        clog(WORLD__CLIENT,"Current location: %s  %0.2f, %0.2f, %0.2f",
                database.GetZoneName(pp.zone_id), pp.x, pp.y, pp.z);
        clog(WORLD__CLIENT,"Bind location: %s  %0.2f, %0.2f, %0.2f",
                database.GetZoneName(pp.binds[0].zoneId), pp.binds[0].x, pp.binds[0].y, pp.binds[0].z);


        // Starting Items inventory
        database.SetStartingItems(&pp, &inv, pp.race, pp.class_, pp.deity, pp.zone_id, pp.name, GetAdmin());


        // now we give the pp and the inv we made to StoreCharacter
        // to see if we can store it
        if (!database.StoreCharacter(GetAccountID(), &pp, &inv, &ext))
        {
                clog(WORLD__CLIENT_ERR,"Character creation failed: %s", pp.name);
                return false;
        }
        else
        {
                clog(WORLD__CLIENT,"Character creation successful: %s", pp.name);
                return true;
        }
}

// returns true if the request is ok, false if there's an error
bool CheckCharCreateInfo(CharCreate_Struct *cc)
{
        int32 bSTR, bSTA, bAGI, bDEX, bWIS, bINT, bCHA, bTOTAL, cTOTAL, stat_points;        //these are all int32 in CharCreate_Struct, so we'll make them int32 here to make the compiler shut up
        int classtemp, racetemp;
        int Charerrors = 0;


// solar: if this is increased you'll have to add a column to the classrace
// table below
#define _TABLE_RACES        16

        static const int BaseRace[_TABLE_RACES][7] =
        {            /* STR  STA  AGI  DEX  WIS  INT  CHR */
        { /*Human*/      75,  75,  75,  75,  75,  75,  75},
        { /*Barbarian*/ 103,  95,  82,  70,  70,  60,  55},
        { /*Erudite*/    60,  70,  70,  70,  83, 107,  70},
        { /*Wood Elf*/  65,  65,  95,  80,  80,  75,  75},
        { /*High Elf*/  55,  65,  85,  70,  95,  92,  80},
        { /*Dark Elf*/  60,  65,  90,  75,  83,  99,  60},
        { /*Half Elf*/  70,  70,  90,  85,  60,  75,  75},
        { /*Dwarf*/      90,  90,  70,  90,  83,  60,  45},
        { /*Troll*/    108, 109,  83,  75,  60,  52,  40},
        { /*Ogre*/      130, 122,  70,  70,  67,  60,  37},
        { /*Halfling*/  70,  75,  95,  90,  80,  67,  50},
        { /*Gnome*/      60,  70,  85,  85,  67,  98,  60},
        { /*Iksar*/      70,  70,  90,  85,  80,  75,  55},
        { /*Vah Shir*/  90,  75,  90,  70,  70,  65,  65},
        { /*Froglok*/    70,  80, 100, 100,  75,  75,  50},
        { /*Drakkin*/    70,  80,  85,  75,  80,  85,  75}
        };

        static const int BaseClass[PLAYER_CLASS_COUNT][8] =
        {              /* STR  STA  AGI  DEX  WIS  INT  CHR  ADD*/
        { /*Warrior*/      10,  10,  5,  0,  0,  0,  0,  25},
        { /*Cleric*/        5,  5,  0,  0,  10,  0,  0,  30},
        { /*Paladin*/      10,  5,  0,  0,  5,  0,  10,  20},
        { /*Ranger*/        5,  10,  10,  0,  5,  0,  0,  20},
        { /*ShadowKnight*/ 10,  5,  0,  0,  0,  10,  5,  20},
        { /*Druid*/        0,  10,  0,  0,  10,  0,  0,  30},
        { /*Monk*/          5,  5,  10,  10,  0,  0,  0,  20},
        { /*Bard*/          5,  0,  0,  10,  0,  0,  10,  25},
        { /*Rouge*/        0,  0,  10,  10,  0,  0,  0,  30},
        { /*Shaman*/        0,  5,  0,  0,  10,  0,  5,  30},
        { /*Necromancer*/  0,  0,  0,  10,  0,  10,  0,  30},
        { /*Wizard*/        0,  10,  0,  0,  0,  10,  0,  30},
        { /*Magician*/      0,  10,  0,  0,  0,  10,  0,  30},
        { /*Enchanter*/    0,  0,  0,  0,  0,  10,  10,  30},
        { /*Beastlord*/    0,  10,  5,  0,  10,  0,  5,  20},
        { /*Berserker*/    10,  5,  0,  10,  0,  0,  0,  25}
        };

        static const bool ClassRaceLookupTable[PLAYER_CLASS_COUNT][_TABLE_RACES]=
        {                  /*Human  Barbarian Erudite Woodelf Highelf Darkelf Halfelf Dwarf  Troll  Ogre  Halfling Gnome  Iksar  Vahshir Froglok Drakkin*/
        { /*Warrior*/        true,  true,    false,  true,  false,  true,  true,  true,  true,  true,  true,    true,  true,  true,  true,  true},
        { /*Cleric*/          true,  false,    true,  false,  true,  true,  true,  true,  false, false, true,    true,  false, false,  true,  true},
        { /*Paladin*/        true,  false,    true,  false,  true,  false,  true,  true,  false, false, true,    true,  false, false,  true,  true},
        { /*Ranger*/          true,  false,    false,  true,  false,  false,  true,  false, false, false, true,    false, false, false,  false,  true},
        { /*ShadowKnight*/    true,  false,    true,  false,  false,  true,  false,  false, true,  true,  false,  true,  true,  false,  true,  true},
        { /*Druid*/          true,  false,    false,  true,  false,  false,  true,  false, false, false, true,    false, false, false,  false,  true},
        { /*Monk*/            true,  false,    false,  false,  false,  false,  false,  false, false, false, false,  false, true,  false,  false,  true},
        { /*Bard*/            true,  false,    false,  true,  false,  false,  true,  false, false, false, false,  false, false, true,  false,  true},
        { /*Rogue*/          true,  true,    false,  true,  false,  true,  true,  true,  false, false, true,    true,  false, true,  true,  true},
        { /*Shaman*/          false, true,    false,  false,  false,  false,  false,  false, true,  true,  false,  false, true,  true,  true,  false},
        { /*Necromancer*/    true,  false,    true,  false,  false,  true,  false,  false, false, false, false,  true,  true,  false,  true,  true},
        { /*Wizard*/          true,  false,    true,  false,  true,  true,  false,  false, false, false, false,  true,  false, false,  true,  true},
        { /*Magician*/        true,  false,    true,  false,  true,  true,  false,  false, false, false, false,  true,  false, false,  false,  true},
        { /*Enchanter*/      true,  false,    true,  false,  true,  true,  false,  false, false, false, false,  true,  false, false,  false,  true},
        { /*Beastlord*/      false, true,    false,  false,  false,  false,  false,  false, true,  true,  false,  false, true,  true,  false,  false},
        { /*Berserker*/      false, true,    false,  false,  false,  false,  false,  true,  true,  true,  false,  false, false, true,  false,  false}
        };//Initial table by kathgar, editted by Wiz for accuracy, solar too

        if(!cc) return false;

        _log(WORLD__CLIENT,"Validating char creation info...");

        classtemp = cc->class_ - 1;
        racetemp = cc->race - 1;
        // these have non sequential race numbers so they need to be mapped
        if (cc->race == FROGLOK) racetemp = 14;
        if (cc->race == VAHSHIR) racetemp = 13;
        if (cc->race == IKSAR) racetemp = 12;
        if (cc->race == DRAKKIN) racetemp = 15;

        // if out of range looking it up in the table would crash stuff
        // so we return from these
        if(classtemp >= PLAYER_CLASS_COUNT)
        {
                _log(WORLD__CLIENT_ERR,"  class is out of range");
                return false;
        }
        if(racetemp >= _TABLE_RACES)
        {
                _log(WORLD__CLIENT_ERR,"  race is out of range");
                return false;
        }

        if(!ClassRaceLookupTable[classtemp][racetemp]) //Lookup table better than a bunch of ifs?
        {
                _log(WORLD__CLIENT_ERR,"  invalid race/class combination");
                // we return from this one, since if it's an invalid combination our table
                // doesn't have meaningful values for the stats
                return false;
        }

        // solar: add up the base values for this class/race
        // this is what they start with, and they have stat_points more
        // that can distributed
        bSTR = BaseClass[classtemp][0] + BaseRace[racetemp][0];
        bSTA = BaseClass[classtemp][1] + BaseRace[racetemp][1];
        bAGI = BaseClass[classtemp][2] + BaseRace[racetemp][2];
        bDEX = BaseClass[classtemp][3] + BaseRace[racetemp][3];
        bWIS = BaseClass[classtemp][4] + BaseRace[racetemp][4];
        bINT = BaseClass[classtemp][5] + BaseRace[racetemp][5];
        bCHA = BaseClass[classtemp][6] + BaseRace[racetemp][6];
        stat_points = BaseClass[classtemp][7];
        bTOTAL = bSTR + bSTA + bAGI + bDEX + bWIS + bINT + bCHA;
        cTOTAL = cc->STR + cc->STA + cc->AGI + cc->DEX + cc->WIS + cc->INT + cc->CHA;

        // solar: the first check makes sure the total is exactly what was expected.
        // this will catch all the stat cheating, but there's still the issue
        // of reducing CHA or INT or something, to use for STR, so we check
        // that none are lower than the base or higher than base + stat_points
        // NOTE: these could just be else if, but i want to see all the stats
        // that are messed up not just the first hit

        if(bTOTAL + stat_points != cTOTAL)
        {
                _log(WORLD__CLIENT_ERR,"  stat points total doesn't match expected value: expecting %d got %d", bTOTAL + stat_points, cTOTAL);
                Charerrors++;
        }

        if(cc->STR > bSTR + stat_points || cc->STR < bSTR)
        {
                _log(WORLD__CLIENT_ERR,"  stat STR is out of range");
                Charerrors++;
        }
        if(cc->STA > bSTA + stat_points || cc->STA < bSTA)
        {
                _log(WORLD__CLIENT_ERR,"  stat STA is out of range");
                Charerrors++;
        }
        if(cc->AGI > bAGI + stat_points || cc->AGI < bAGI)
        {
                _log(WORLD__CLIENT_ERR,"  stat AGI is out of range");
                Charerrors++;
        }
        if(cc->DEX > bDEX + stat_points || cc->DEX < bDEX)
        {
                _log(WORLD__CLIENT_ERR,"  stat DEX is out of range");
                Charerrors++;
        }
        if(cc->WIS > bWIS + stat_points || cc->WIS < bWIS)
        {
                _log(WORLD__CLIENT_ERR,"  stat WIS is out of range");
                Charerrors++;
        }
        if(cc->INT > bINT + stat_points || cc->INT < bINT)
        {
                _log(WORLD__CLIENT_ERR,"  stat INT is out of range");
                Charerrors++;
        }
        if(cc->CHA > bCHA + stat_points || cc->CHA < bCHA)
        {
                _log(WORLD__CLIENT_ERR,"  stat CHA is out of range");
                Charerrors++;
        }

        /*TODO: Check for deity/class/race.. it'd be nice, but probably of any real use to hack(faction, deity based items are all I can think of)
        I am NOT writing those tables - kathgar*/

        _log(WORLD__CLIENT,"Found %d errors in character creation request", Charerrors);

        return Charerrors == 0;
}

void Client::SetClassStartingSkills( PlayerProfile_Struct *pp )
{
  switch( pp->class_ )
  {
  case BARD:
      {
        pp->skills[_1H_SLASHING] = 5;
        pp->skills[SINGING] = 5;
        break;
      }
  case BEASTLORD:
      {
        pp->skills[HAND_TO_HAND] = 5;
        break;
      }
  case BERSERKER: // A Guess
      {
        pp->skills[_2H_SLASHING] = 5;
        break;
      }
  case CLERIC:
      {
        pp->skills[_1H_BLUNT] = 5;
        break;
      }
  case DRUID:
      {
        pp->skills[_1H_BLUNT] = 5;
        break;
      }
  case ENCHANTER:
      {
        pp->skills[PIERCING] = 5;
        break;
      }
  case MAGICIAN:
      {
        pp->skills[PIERCING] = 5;
        break;
      }
  case MONK:
      {
        pp->skills[DODGE] = 5;
        pp->skills[DUAL_WIELD] = 5;
        pp->skills[HAND_TO_HAND] = 5;
        break;
      }
  case NECROMANCER:
      {
        pp->skills[PIERCING] = 5;
        break;
      }
  case PALADIN:
      {
        pp->skills[_1H_SLASHING] = 5;
        break;
      }
  case RANGER:
      {
        pp->skills[_1H_SLASHING] = 5;
        break;
      }
  case ROGUE:
      {
        pp->skills[PIERCING] = 5;
        pp->languages[LANG_THIEVES_CANT] = 100; // Thieves Cant
        break;
      }
  case SHADOWKNIGHT:
      {
        pp->skills[_1H_SLASHING] = 5;
        break;
      }
  case SHAMAN:
      {
        pp->skills[_1H_BLUNT] = 5;
        break;
      }
  case WARRIOR:
      {
        pp->skills[_1H_SLASHING] = 5;
        break;
      }
  case WIZARD:
      {
        pp->skills[PIERCING] = 5;
        break;
      }
  }
}

void Client::SetRaceStartingSkills( PlayerProfile_Struct *pp )
{
  switch( pp->race )
  {
  case BARBARIAN:
  case DWARF:
  case ERUDITE:
  case HALF_ELF:
  case HIGH_ELF:
  case HUMAN:
  case OGRE:
  case TROLL:
  case DRAKKIN:        //Drakkin are supposed to get a starting AA Skill
      {
        // No Race Specific Skills
        break;
      }
  case DARK_ELF:
      {
        pp->skills[HIDE] = 50;
        break;
      }
  case FROGLOK:
      {
        pp->skills[SWIMMING] = 125;
        break;
      }
  case GNOME:
      {
        pp->skills[TINKERING] = 50;
        break;
      }
  case HALFLING:
      {
        pp->skills[HIDE] = 50;
        pp->skills[SNEAK] = 50;
        break;
      }
  case IKSAR:
      {
        pp->skills[FORAGE] = 50;
        pp->skills[SWIMMING] = 100;
        break;
      }
  case WOOD_ELF:
      {
        pp->skills[FORAGE] = 50;
        pp->skills[HIDE] = 50;
        break;
      }
  case VAHSHIR:
      {
        pp->skills[SAFE_FALL] = 50;
        pp->skills[SNEAK] = 50;
        break;
      }
  }
}

void Client::SetRacialLanguages( PlayerProfile_Struct *pp )
{
  switch( pp->race )
  {
  case BARBARIAN:
      {
        pp->languages[LANG_COMMON_TONGUE] = 100;
        pp->languages[LANG_BARBARIAN] = 100;
        break;
      }
  case DARK_ELF:
      {
        pp->languages[LANG_COMMON_TONGUE] = 100;
        pp->languages[LANG_DARK_ELVISH] = 100;
        pp->languages[LANG_DARK_SPEECH] = 100;
        pp->languages[LANG_ELDER_ELVISH] = 100;
        pp->languages[LANG_ELVISH] = 25;
        break;
      }
  case DWARF:
      {
        pp->languages[LANG_COMMON_TONGUE] = 100;
        pp->languages[LANG_DWARVISH] = 100;
        pp->languages[LANG_GNOMISH] = 25;
        break;
      }
  case ERUDITE:
      {
        pp->languages[LANG_COMMON_TONGUE] = 100;
        pp->languages[LANG_ERUDIAN] = 100;
        break;
      }
  case FROGLOK:
      {
        pp->languages[LANG_COMMON_TONGUE] = 100;
        pp->languages[LANG_FROGLOK] = 100;
        pp->languages[LANG_TROLL] = 25;
        break;
      }
  case GNOME:
      {
        pp->languages[LANG_COMMON_TONGUE] = 100;
        pp->languages[LANG_DWARVISH] = 25;
        pp->languages[LANG_GNOMISH] = 100;
        break;
      }
  case HALF_ELF:
      {
        pp->languages[LANG_COMMON_TONGUE] = 100;
        pp->languages[LANG_ELVISH] = 100;
        break;
      }
  case HALFLING:
      {
        pp->languages[LANG_COMMON_TONGUE] = 100;
        pp->languages[LANG_HALFLING] = 100;
        break;
      }
  case HIGH_ELF:
      {
        pp->languages[LANG_COMMON_TONGUE] = 100;
        pp->languages[LANG_DARK_ELVISH] = 25;
        pp->languages[LANG_ELDER_ELVISH] = 25;
        pp->languages[LANG_ELVISH] = 100;
        break;
      }
  case HUMAN:
      {
        pp->languages[LANG_COMMON_TONGUE] = 100;
        break;
      }
  case IKSAR:
      {
        pp->languages[LANG_COMMON_TONGUE] = 95;
        pp->languages[LANG_DARK_SPEECH] = 100;
        pp->languages[LANG_LIZARDMAN] = 100;
        break;
      }
  case OGRE:
      {
        pp->languages[LANG_COMMON_TONGUE] = 95;
        pp->languages[LANG_DARK_SPEECH] = 100;
        pp->languages[LANG_OGRE] = 100;
        break;
      }
  case TROLL:
      {
        pp->languages[LANG_COMMON_TONGUE] = 95;
        pp->languages[LANG_DARK_SPEECH] = 100;
        pp->languages[LANG_TROLL] = 100;
        break;
      }
  case WOOD_ELF:
      {
        pp->languages[LANG_COMMON_TONGUE] = 100;
        pp->languages[LANG_ELVISH] = 100;
        break;
      }
  case VAHSHIR:
      {
        pp->languages[LANG_COMMON_TONGUE] = 100;
        pp->languages[LANG_COMBINE_TONGUE] = 100;
        pp->languages[LANG_ERUDIAN] = 25;
        pp->languages[LANG_VAH_SHIR] = 100;
        break;
      }
  case DRAKKIN:
      {
        pp->languages[LANG_COMMON_TONGUE] = 100;
        pp->languages[LANG_ELDER_DRAGON] = 100;
        pp->languages[LANG_DRAGON] = 100;
        break;
      }
  }
}

Note: client.cpp also includes a fix for dual MOTD, so you need to add the variable;
Code:

INSERT INTO `variables` VALUES ('MOTDEqEmu','Welcome to AXCLASSIC!','Server Message of the Day','2010-01-08 13:19:53');
So you can specify different MOTDs on different LS.

cliententry.cpp
Code:

#include "../common/debug.h"
#include "cliententry.h"
#include "clientlist.h"
#include "LoginServer.h"
#include "worlddb.h"
#include "zoneserver.h"
#include "WorldConfig.h"
#include "../common/guilds.h"
extern int32 numplayers;
extern LoginServer loginserver;
extern ClientList                client_list;
extern volatile bool RunLoops;

ClientListEntry::ClientListEntry(int32 in_id, int32 iLSID, const char* iLoginName, const char* iLoginKey, sint16 iWorldAdmin, int32 ip, uint8 local)
: id(in_id)
{
        ClearVars(true);
       
        pIP = ip;
        pLSID = iLSID;
        if(iLSID > 0)
                paccountid = database.GetAccountIDFromLSID(iLSID, paccountname, &padmin);
        strn0cpy(plsname, iLoginName, sizeof(plsname));
        strn0cpy(plskey, iLoginKey, sizeof(plskey));
        pworldadmin = iWorldAdmin;
        plocal=(local==1);

        pinstance = 0;
}

ClientListEntry::ClientListEntry(int32 in_id, int32 iAccID, const char* iAccName, MD5& iMD5Pass, sint16 iAdmin)
: id(in_id)
{
        ClearVars(true);
       
        pIP = 0;
        pLSID = 0;
        pworldadmin = 0;

        paccountid = iAccID;
        strn0cpy(paccountname, iAccName, sizeof(paccountname));
        pMD5Pass = iMD5Pass;
        padmin = iAdmin;

        pinstance = 0;
}

ClientListEntry::ClientListEntry(int32 in_id, ZoneServer* iZS, ServerClientList_Struct* scl, sint8 iOnline)
: id(in_id)
{
        ClearVars(true);
       
        pIP = 0;
        pLSID = scl->LSAccountID;
        strn0cpy(plsname, scl->name, sizeof(plsname));
        strn0cpy(plskey, scl->lskey, sizeof(plskey));
        pworldadmin = 0;

        paccountid = scl->AccountID;
        strn0cpy(paccountname, scl->AccountName, sizeof(paccountname));
        padmin = scl->Admin;

        pinstance = 0;

        if (iOnline >= CLE_Status_Zoning)
                Update(iZS, scl, iOnline);
        else
                SetOnline(iOnline);
}

ClientListEntry::~ClientListEntry() {
        if (RunLoops) {
                Camp(); // updates zoneserver's numplayers
                client_list.RemoveCLEReferances(this);
        }
}

void ClientListEntry::SetChar(int32 iCharID, const char* iCharName) {
        pcharid = iCharID;
        strn0cpy(pname, iCharName, sizeof(pname));
}

void ClientListEntry::SetOnline(ZoneServer* iZS, sint8 iOnline) {
        if (iZS == this->Server())
                SetOnline(iOnline);
}

void ClientListEntry::SetOnline(sint8 iOnline) {
        if (iOnline >= CLE_Status_Online && pOnline < CLE_Status_Online)
                numplayers++;
        else if (iOnline < CLE_Status_Online && pOnline >= CLE_Status_Online) {
                numplayers--;
        }
        if (iOnline != CLE_Status_Online || pOnline < CLE_Status_Online)
                pOnline = iOnline;
        if (iOnline < CLE_Status_Zoning)
                Camp();
        if (pOnline >= CLE_Status_Online)
                stale = 0;
}
void ClientListEntry::LSUpdate(ZoneServer* iZS){
        if(WorldConfig::get()->UpdateStats){
                ServerPacket* pack = new ServerPacket;
                pack->opcode = ServerOP_LSZoneInfo;
                pack->size = sizeof(ZoneInfo_Struct);
                pack->pBuffer = new uchar[pack->size];
                ZoneInfo_Struct* zone =(ZoneInfo_Struct*)pack->pBuffer;
                zone->count=iZS->NumPlayers();
                zone->zone = iZS->GetZoneID();
                zone->zone_wid = iZS->GetID();

#ifdef DUAL_SERVER
                loginserver.SendPacket2(pack);
#else
                loginserver.SendPacket(pack);
#endif

                safe_delete(pack);
        }
}
void ClientListEntry::LSZoneChange(ZoneToZone_Struct* ztz){
        if(WorldConfig::get()->UpdateStats){
                ServerPacket* pack = new ServerPacket;
                pack->opcode = ServerOP_LSPlayerZoneChange;
                pack->size = sizeof(ServerLSPlayerZoneChange_Struct);
                pack->pBuffer = new uchar[pack->size];
                ServerLSPlayerZoneChange_Struct* zonechange =(ServerLSPlayerZoneChange_Struct*)pack->pBuffer;
                zonechange->lsaccount_id = LSID();
                zonechange->from = ztz->current_zone_id;
                zonechange->to = ztz->requested_zone_id;
                loginserver.SendPacket(pack);

#ifdef DUAL_SERVER
                loginserver.SendPacket2(pack);
#endif

                safe_delete(pack);
        }
}
void ClientListEntry::Update(ZoneServer* iZS, ServerClientList_Struct* scl, sint8 iOnline) {
        if (pzoneserver != iZS) {
                if (pzoneserver){
                        pzoneserver->RemovePlayer();
                        LSUpdate(pzoneserver);
                }
                if (iZS){
                        iZS->AddPlayer();
                        LSUpdate(iZS);
                }
        }
        pzoneserver = iZS;
        pzone = scl->zone;
        pinstance = scl->instance_id;
        pcharid = scl->charid;

        strcpy(pname, scl->name);
        if (paccountid == 0) {
                paccountid = scl->AccountID;
                strcpy(paccountname, scl->AccountName);
                strcpy(plsname, scl->AccountName);
                pIP = scl->IP;
                pLSID = scl->LSAccountID;
                strn0cpy(plskey, scl->lskey, sizeof(plskey));
        }
        padmin = scl->Admin;
        plevel = scl->level;
        pclass_ = scl->class_;
        prace = scl->race;
        panon = scl->anon;
        ptellsoff = scl->tellsoff;
        pguild_id = scl->guild_id;
        pLFG = scl->LFG;
        gm = scl->gm;
        // Fields from the LFG Window
        if((scl->LFGFromLevel != 0) && (scl->LFGToLevel != 0)) {
                pLFGFromLevel = scl->LFGFromLevel;
                pLFGToLevel = scl->LFGToLevel;
                pLFGMatchFilter = scl->LFGMatchFilter;
                memcpy(pLFGComments, scl->LFGComments, sizeof(pLFGComments));
        }

        SetOnline(iOnline);
}

void ClientListEntry::LeavingZone(ZoneServer* iZS, sint8 iOnline) {
        if (iZS != 0 && iZS != pzoneserver)
                return;
        SetOnline(iOnline);

        if (pzoneserver){
                pzoneserver->RemovePlayer();
                LSUpdate(pzoneserver);
        }
        pzoneserver = 0;
        pzone = 0;
}

void ClientListEntry::ClearVars(bool iAll) {
        if (iAll) {
                pOnline = CLE_Status_Never;
                stale = 0;

                pLSID = 0;
                memset(plsname, 0, sizeof(plsname));
                memset(plskey, 0, sizeof(plskey));
                pworldadmin = 0;

                paccountid = 0;
                memset(paccountname, 0, sizeof(paccountname));
                padmin = 0;
        }
        pzoneserver = 0;
        pzone = 0;
        pcharid = 0;
        memset(pname, 0, sizeof(pname));
        plevel = 0;
        pclass_ = 0;
        prace = 0;
        panon = 0;
        ptellsoff = 0;
        pguild_id = GUILD_NONE;
        pLFG = 0;
        gm = 0;
}

void ClientListEntry::Camp(ZoneServer* iZS) {
        if (iZS != 0 && iZS != pzoneserver)
                return;
        if (pzoneserver){
                pzoneserver->RemovePlayer();
                LSUpdate(pzoneserver);
        }

        ClearVars();

        stale = 0;
}

bool ClientListEntry::CheckStale() {
        stale++;
        if (stale >= 3) {
                if (pOnline > CLE_Status_Offline)
                        SetOnline(CLE_Status_Offline);
                else
                        return true;
        }
        return false;
}

bool ClientListEntry::CheckAuth(int32 iLSID, const char* iKey) {
//        if (LSID() == iLSID && strncmp(plskey, iKey,10) == 0) {
        if (strncmp(plskey, iKey,10) == 0) {
                if (paccountid == 0 && LSID()>0) {
                        sint16 tmpStatus = WorldConfig::get()->DefaultStatus;
                        paccountid = database.CreateAccount(plsname, 0, tmpStatus, LSID());
                        if (!paccountid) {
                                _log(WORLD__CLIENTLIST_ERR,"Error adding local account for LS login: '%s', either duplicate name or adding a second LS account will do this, if latter, try again." ,plsname);
                                return false;
                        }
                        strn0cpy(paccountname, plsname, sizeof(paccountname));
                        padmin = tmpStatus;
                }
                char lsworldadmin[15] = "0";
                database.GetVariable("honorlsworldadmin", lsworldadmin, sizeof(lsworldadmin));
                if (atoi(lsworldadmin) == 1 && pworldadmin != 0 && (padmin < pworldadmin || padmin == 0))
                        padmin = pworldadmin;
                return true;
        }
        return false;
}

bool ClientListEntry::CheckAuth(const char* iName, MD5& iMD5Password) {
        if (LSAccountID() == 0 && strcmp(paccountname, iName) == 0 && pMD5Pass == iMD5Password)
                return true;
        return false;
}

bool ClientListEntry::CheckAuth(int32 id, const char* iKey, int32 ip) {
        if (pIP==ip && strncmp(plskey, iKey,10) == 0){
                paccountid = id;
                database.GetAccountFromID(id,paccountname,&padmin);
                return true;
        }
        return false;
}

zoneserver.cpp
Code:

#include "../common/debug.h"
#include "zoneserver.h"
#include "clientlist.h"
#include "LoginServer.h"
#include "zonelist.h"
#include "worlddb.h"
#include "console.h"
#include "client.h"
#include "../common/md5.h"
#include "WorldConfig.h"
#include "../common/guilds.h"
#include "../common/packet_dump.h"
#include "../common/misc.h"
#include "cliententry.h"
#include "wguild_mgr.h"
#include "lfplist.h"
extern ClientList        client_list;
extern GroupLFPList LFPGroupList;
extern ZSList                zoneserver_list;
extern ConsoleList                console_list;
extern LoginServer loginserver;
extern volatile bool RunLoops;

ZoneServer::ZoneServer(EmuTCPConnection* itcpc)
: WorldTCPConnection(), tcpc(itcpc), ls_zboot(5000) {
        ID = zoneserver_list.GetNextID();
        memset(zone_name, 0, sizeof(zone_name));
        memset(compiled, 0, sizeof(compiled));
        zoneID = 0;
        instanceID = 0;

        memset(clientaddress, 0, sizeof(clientaddress));
        clientport = 0;
        BootingUp = false;
        authenticated = false;
        staticzone = false;
        pNumPlayers = 0;
}

ZoneServer::~ZoneServer() {
        if (RunLoops)
                client_list.CLERemoveZSRef(this);
        tcpc->Free();
}

bool ZoneServer::SetZone(int32 iZoneID, int32 iInstanceID, bool iStaticZone) {
        BootingUp = false;
       
        const char* zn = MakeLowerString(database.GetZoneName(iZoneID));
        char*        longname;

        if (iZoneID)
                zlog(WORLD__ZONE,"Setting to '%s' (%d:%d)%s",(zn) ? zn : "",iZoneID, iInstanceID,
                        iStaticZone ? " (Static)" : "");

        zoneID = iZoneID;
        instanceID = iInstanceID;
        if(iZoneID!=0)
                oldZoneID = iZoneID;
        if (zoneID == 0) {
                client_list.CLERemoveZSRef(this);
                pNumPlayers = 0;
                LSSleepUpdate(GetPrevZoneID());
        }

        staticzone = iStaticZone;

        if (zn)
        {
                strcpy(zone_name, zn);
                if( database.GetZoneLongName( (char*)zone_name, &longname, NULL, NULL, NULL, NULL, NULL, NULL ) )
                {
                        strcpy(long_name, longname);
                        safe_delete( longname );
                }
                else
                        strcpy(long_name, "");
        }
        else
        {
                strcpy(zone_name, "");
                strcpy(long_name, "");
        }       

        client_list.ZoneBootup(this);
        ls_zboot.Start();

        return true;
}

void ZoneServer::LSShutDownUpdate(int32 zoneid){
        if(WorldConfig::get()->UpdateStats){
                ServerPacket* pack = new ServerPacket;
                pack->opcode = ServerOP_LSZoneShutdown;
                pack->size = sizeof(ZoneShutdown_Struct);
                pack->pBuffer = new uchar[pack->size];
                memset(pack->pBuffer,0,pack->size);
                ZoneShutdown_Struct* zsd =(ZoneShutdown_Struct*)pack->pBuffer;
                if(zoneid==0)
                        zsd->zone = GetPrevZoneID();
                else
                        zsd->zone = zoneid;
                zsd->zone_wid = GetID();
                loginserver.SendPacket(pack);
               
#ifdef DUAL_SERVER
                loginserver.SendPacket2(pack);
#endif

                safe_delete(pack);
        }
}
void ZoneServer::LSBootUpdate(int32 zoneid, int32 instanceid, bool startup){
        if(WorldConfig::get()->UpdateStats){
                ServerPacket* pack = new ServerPacket;
                if(startup)
                        pack->opcode = ServerOP_LSZoneStart;
                else
                        pack->opcode = ServerOP_LSZoneBoot;
                pack->size = sizeof(ZoneBoot_Struct);
                pack->pBuffer = new uchar[pack->size];
                memset(pack->pBuffer,0,pack->size);
                ZoneBoot_Struct* bootup =(ZoneBoot_Struct*)pack->pBuffer;
                if(startup)
                        strcpy(bootup->compile_time,GetCompileTime());
                bootup->zone = zoneid;
                bootup->zone_wid = GetID();
                bootup->instance = instanceid;
                loginserver.SendPacket(pack);

#ifdef DUAL_SERVER
                loginserver.SendPacket2(pack);
#endif
                safe_delete(pack);
        }
}

void ZoneServer::LSSleepUpdate(int32 zoneid){
        if(WorldConfig::get()->UpdateStats){
                ServerPacket* pack = new ServerPacket;
                pack->opcode = ServerOP_LSZoneSleep;
                pack->size = sizeof(ServerLSZoneSleep_Struct);
                pack->pBuffer = new uchar[pack->size];
                memset(pack->pBuffer,0,pack->size);
                ServerLSZoneSleep_Struct* sleep =(ServerLSZoneSleep_Struct*)pack->pBuffer;
                sleep->zone = zoneid;
                sleep->zone_wid = GetID();
                loginserver.SendPacket(pack);

#ifdef DUAL_SERVER
                loginserver.SendPacket2(pack);
#endif

                safe_delete(pack);
        }
}

bool ZoneServer::Process() {
        if (!tcpc->Connected())
                return false;
        if(ls_zboot.Check()){
                LSBootUpdate(GetZoneID(), true);
                ls_zboot.Disable();
        }
        ServerPacket *pack = 0;
        while((pack = tcpc->PopPacket())) {
                _hex(WORLD__ZONE_TRACE,pack->pBuffer,pack->size);
                if (!authenticated) {
                        if (WorldConfig::get()->SharedKey.length() > 0) {
                                if (pack->opcode == ServerOP_ZAAuth && pack->size == 16) {
                                        int8 tmppass[16];
                                        MD5::Generate((const uchar*) WorldConfig::get()->SharedKey.c_str(), WorldConfig::get()->SharedKey.length(), tmppass);
                                        if (memcmp(pack->pBuffer, tmppass, 16) == 0)
                                                authenticated = true;
                                        else {
                                                struct in_addr  in;
                                                in.s_addr = GetIP();
                                                zlog(WORLD__ZONE_ERR,"Zone authorization failed.");
                                                ServerPacket* pack = new ServerPacket(ServerOP_ZAAuthFailed);
                                                SendPacket(pack);
                                                delete pack;
                                                Disconnect();
                                                return false;
                                        }
                                }
                                else {
                                        struct in_addr  in;
                                        in.s_addr = GetIP();
                                        zlog(WORLD__ZONE_ERR,"Zone authorization failed.");
                                        ServerPacket* pack = new ServerPacket(ServerOP_ZAAuthFailed);
                                        SendPacket(pack);
                                        delete pack;
                                        Disconnect();
                                        return false;
                                }
                        }
                        else
                        {
                                _log(WORLD__ZONE,"**WARNING** You have not configured a world shared key in your config file. You should add a <key>STRING</key> element to your <world> element to prevent unauthroized zone access.");
                                authenticated = true;
                        }
                }
                switch(pack->opcode) {
                case 0:
                        break;
                case ServerOP_KeepAlive: {
                        // ignore this
                        break;
                }
                case ServerOP_ZAAuth: {
                        break;
                }
                case ServerOP_LSZoneBoot:{
                        if(pack->size==sizeof(ZoneBoot_Struct)){
                                ZoneBoot_Struct* zbs= (ZoneBoot_Struct*)pack->pBuffer;
                                SetCompile(zbs->compile_time);
                        }
                        break;
                }
                /*
                case ServerOP_SendGroup: {
                        SendGroup_Struct* sgs=(SendGroup_Struct*)pack->pBuffer;
                        ZoneServer* zs=zoneserver_list.FindByZoneID(sgs->zoneid);
                        if(!zs)
                                zlog(WORLD__ZONE,"Could not find zone id: %i running to transfer group to!",sgs->zoneid);
                        else{
                                zs->SendPacket(pack);
                        }
                        break;
                }*/
                case ServerOP_GroupIDReq: {
                        SendGroupIDs();
                        break;
                }
                case ServerOP_GroupLeave: {
                        if(pack->size != sizeof(ServerGroupLeave_Struct))
                                break;
                        zoneserver_list.SendPacket(pack); //bounce it to all zones
                        break;
                }

                case ServerOP_GroupJoin: {
                        if(pack->size != sizeof(ServerGroupJoin_Struct))
                                break;
                        zoneserver_list.SendPacket(pack); //bounce it to all zones
                        break;
                }

                case ServerOP_ForceGroupUpdate: {
                        if(pack->size != sizeof(ServerForceGroupUpdate_Struct))
                                break;
                        zoneserver_list.SendPacket(pack); //bounce it to all zones
                        break;
                }

                case ServerOP_OOZGroupMessage: {
                        zoneserver_list.SendPacket(pack); //bounce it to all zones
                        break;
                }

                case ServerOP_DisbandGroup: {
                        if(pack->size != sizeof(ServerDisbandGroup_Struct))
                                break;
                        zoneserver_list.SendPacket(pack); //bounce it to all zones
                        break;
                }

                case ServerOP_RaidAdd:{
                        if(pack->size != sizeof(ServerRaidGeneralAction_Struct))
                                break;

                        zoneserver_list.SendPacket(pack);
                        break;
                }

                case ServerOP_RaidRemove: {
                        if(pack->size != sizeof(ServerRaidGeneralAction_Struct))
                                break;

                        zoneserver_list.SendPacket(pack);
                        break;
                }

                case ServerOP_RaidDisband: {
                        if(pack->size != sizeof(ServerRaidGeneralAction_Struct))
                                break;

                        zoneserver_list.SendPacket(pack);
                        break;
                }

                case ServerOP_RaidLockFlag: {
                        if(pack->size != sizeof(ServerRaidGeneralAction_Struct))
                                break;

                        zoneserver_list.SendPacket(pack);
                        break;
                }

                case ServerOP_RaidChangeGroup: {
                        if(pack->size != sizeof(ServerRaidGeneralAction_Struct))
                                break;

                        zoneserver_list.SendPacket(pack);
                        break;
                }

                case ServerOP_UpdateGroup: {
                        if(pack->size != sizeof(ServerRaidGeneralAction_Struct))
                                break;

                        zoneserver_list.SendPacket(pack);
                        break;
                }

                case ServerOP_RaidGroupDisband: {
                        if(pack->size != sizeof(ServerRaidGeneralAction_Struct))
                                break;

                        zoneserver_list.SendPacket(pack);
                        break;
                }

                case ServerOP_RaidGroupAdd: {
                        if(pack->size != sizeof(ServerRaidGroupAction_Struct))
                                break;

                        zoneserver_list.SendPacket(pack);
                        break;
                }

                case ServerOP_RaidGroupRemove: {
                        if(pack->size != sizeof(ServerRaidGroupAction_Struct))
                                break;

                        zoneserver_list.SendPacket(pack);
                        break;
                }

                case ServerOP_RaidGroupSay: {
                        zoneserver_list.SendPacket(pack);
                        break;
                }

                case ServerOP_RaidSay: {
                        zoneserver_list.SendPacket(pack);
                        break;
                }

                case ServerOP_RaidGroupLeader: {
                        if(pack->size != sizeof(ServerRaidGeneralAction_Struct))
                                break;

                        zoneserver_list.SendPacket(pack);
                        break;
                }

                case ServerOP_RaidLeader: {
                        if(pack->size != sizeof(ServerRaidGeneralAction_Struct))
                                break;

                        zoneserver_list.SendPacket(pack);
                        break;
                }

                case ServerOP_DetailsChange: {
                        if(pack->size != sizeof(ServerRaidGeneralAction_Struct))
                                break;

                        zoneserver_list.SendPacket(pack);
                        break;
                }

                case ServerOP_SpawnCondition: {
                        if(pack->size != sizeof(ServerSpawnCondition_Struct))
                                break;
                        //bounce the packet to the correct zone server, if its up
                        ServerSpawnCondition_Struct* ssc = (ServerSpawnCondition_Struct*)pack->pBuffer;
                        zoneserver_list.SendPacket(ssc->zoneID, 0, pack);
                        break;
                }
                case ServerOP_SpawnEvent: {
                        if(pack->size != sizeof(ServerSpawnEvent_Struct))
                                break;
                        //bounce the packet to the correct zone server, if its up
                        ServerSpawnEvent_Struct* sse = (ServerSpawnEvent_Struct*)pack->pBuffer;
                        zoneserver_list.SendPacket(sse->zoneID, 0, pack);
                        break;
                }
                case ServerOP_ChannelMessage: {
                        ServerChannelMessage_Struct* scm = (ServerChannelMessage_Struct*) pack->pBuffer;
                        if (scm->chan_num == 7 || scm->chan_num == 14) {
                                if (scm->deliverto[0] == '*') {
                                        Console* con = 0;
                                        con = console_list.FindByAccountName(&scm->deliverto[1]);
                                        if (((!con) || (!con->SendChannelMessage(scm))) && (!scm->noreply))
                                                zoneserver_list.SendEmoteMessage(scm->from, 0, 0, 0, "You told %s, '%s is not online at this time'", scm->to, scm->to);
                                        break;
                                }
                                ClientListEntry* cle = client_list.FindCharacter(scm->deliverto);
                                if (cle == 0 || cle->Online() < CLE_Status_Zoning || (cle->TellsOff() && ((cle->Anon() == 1 && scm->fromadmin < cle->Admin()) || scm->fromadmin < 80))) {
                                        if (!scm->noreply)
                                                zoneserver_list.SendEmoteMessage(scm->from, 0, 0, 0, "You told %s, '%s is not online at this time'", scm->to, scm->to);
                                }
                                else if (cle->Online() == CLE_Status_Zoning) {
                                        if (!scm->noreply) {
                                                char errbuf[MYSQL_ERRMSG_SIZE];
                                                char *query = 0;
                                                MYSQL_RES *result;
                                                //MYSQL_ROW row;  Trumpcard - commenting.  Currently unused.
                                                time_t rawtime;
                                                struct tm * timeinfo;
                                                time ( &rawtime );
                                                timeinfo = localtime ( &rawtime );
                                                char *telldate=asctime(timeinfo);
                                                if (database.RunQuery(query, MakeAnyLenString(&query, "SELECT name from character_ where name='%s'",scm->deliverto), errbuf, &result)) {
                                                        safe_delete(query);
                                                        if (result!=0) {
                                                                if (database.RunQuery(query, MakeAnyLenString(&query, "INSERT INTO tellque (Date,Receiver,Sender,Message) values('%s','%s','%s','%s')",telldate,scm->deliverto,scm->from,scm->message), errbuf, &result))
                                                                        zoneserver_list.SendEmoteMessage(scm->from, 0, 0, 0, "Your message has been added to the %s's que.", scm->to);
                                                                else
                                                                        zoneserver_list.SendEmoteMessage(scm->from, 0, 0, 0, "You told %s, '%s is not online at this time'", scm->to, scm->to);
                                                                safe_delete(query);
                                                        }
                                                        else
                                                                zoneserver_list.SendEmoteMessage(scm->from, 0, 0, 0, "You told %s, '%s is not online at this time'", scm->to, scm->to);
                                                        mysql_free_result(result);
                                                }
                                                else
                                                        safe_delete(query);
                                        }
                                //                zoneserver_list.SendEmoteMessage(scm->from, 0, 0, 0, "You told %s, '%s is not online at this time'", scm->to, scm->to);
                                }
                                else if (cle->Server() == 0) {
                                        if (!scm->noreply)
                                                zoneserver_list.SendEmoteMessage(scm->from, 0, 0, 0, "You told %s, '%s is not contactable at this time'", scm->to, scm->to);
                                }
                                else
                                        cle->Server()->SendPacket(pack);
                        }
                        else {
                                if (scm->chan_num == 5 || scm->chan_num == 6 || scm->chan_num == 11) {
                                        console_list.SendChannelMessage(scm);
                                }
                                zoneserver_list.SendPacket(pack);
                        }
                        break;
                }
                case ServerOP_EmoteMessage: {
                        ServerEmoteMessage_Struct* sem = (ServerEmoteMessage_Struct*) pack->pBuffer;
                        zoneserver_list.SendEmoteMessageRaw(sem->to, sem->guilddbid, sem->minstatus, sem->type, sem->message);
                        break;
                }
                case ServerOP_VoiceMacro: {

                        ServerVoiceMacro_Struct* svm = (ServerVoiceMacro_Struct*) pack->pBuffer;
                       
                        if(svm->Type == VoiceMacroTell) {

                                ClientListEntry* cle = client_list.FindCharacter(svm->To);

                                if (!cle || (cle->Online() < CLE_Status_Zoning) || !cle->Server())  {

                                        zoneserver_list.SendEmoteMessage(svm->From, 0, 0, 0, "'%s is not online at this time'", svm->To);

                                        break;
                                }

                                cle->Server()->SendPacket(pack);
                        }
                        else
                                zoneserver_list.SendPacket(pack);

                        break;
                }

                case ServerOP_RezzPlayerAccept: {
                        zoneserver_list.SendPacket(pack);
                        break;
                }
                case ServerOP_RezzPlayer: {

                        RezzPlayer_Struct* sRezz = (RezzPlayer_Struct*) pack->pBuffer;
                        if (zoneserver_list.SendPacket(pack)){
                                zlog(WORLD__ZONE,"Sent Rez packet for %s",sRezz->rez.your_name);
                        }
                        else {
                                zlog(WORLD__ZONE,"Could not send Rez packet for %s",sRezz->rez.your_name);
                        }
                        break;
                }
                case ServerOP_MultiLineMsg: {
                        ServerMultiLineMsg_Struct* mlm = (ServerMultiLineMsg_Struct*) pack->pBuffer;
                        client_list.SendPacket(mlm->to, pack);
                        break;
                }
                case ServerOP_SetZone: {
                        if(pack->size != sizeof(SetZone_Struct))
                                break;

                        SetZone_Struct* szs = (SetZone_Struct*) pack->pBuffer;       
                        if (szs->zoneid != 0) {
                                if(database.GetZoneName(szs->zoneid))
                                        SetZone(szs->zoneid, szs->instanceid, szs->staticzone);
                                else
                                        SetZone(0);
                        }
                        else
                                SetZone(0);

                        break;
                }
                case ServerOP_SetConnectInfo: {
                        if (pack->size != sizeof(ServerConnectInfo))
                                        break;
                        ServerConnectInfo* sci = (ServerConnectInfo*) pack->pBuffer;

                        if (!sci->port) {
                                clientport=zoneserver_list.GetAvailableZonePort();

                                ServerPacket p(ServerOP_SetConnectInfo, sizeof(ServerConnectInfo));
                                memset(p.pBuffer,0,sizeof(ServerConnectInfo));
                                ServerConnectInfo* sci = (ServerConnectInfo*) p.pBuffer;
                                sci->port = clientport;
                                SendPacket(&p);
                                zlog(WORLD__ZONE,"Auto zone port configuration.  Telling zone to use port %d",clientport);
                        } else {
                                clientport=sci->port;
                                zlog(WORLD__ZONE,"Zone specified port %d, must be a previously allocated zone reconnecting.",clientport);
                        }

                }
                case ServerOP_SetLaunchName: {
                        if(pack->size != sizeof(LaunchName_Struct))
                                break;
                        const LaunchName_Struct* ln = (const LaunchName_Struct*)pack->pBuffer;
                        launcher_name = ln->launcher_name;
                        launched_name = ln->zone_name;
                        zlog(WORLD__ZONE, "Zone started with name %s by launcher %s", launched_name.c_str(), launcher_name.c_str());
                        break;
                }
                case ServerOP_ShutdownAll: {
                        if(pack->size==0){
                                zoneserver_list.SendPacket(pack);
                                zoneserver_list.Process();
                                CatchSignal(2);
                        }
                        else{
                                WorldShutDown_Struct* wsd=(WorldShutDown_Struct*)pack->pBuffer;
                                if(wsd->time==0 && wsd->interval==0 && zoneserver_list.shutdowntimer->Enabled()){
                                        zoneserver_list.shutdowntimer->Disable();
                                        zoneserver_list.reminder->Disable();
                                }
                                else{
                                        zoneserver_list.shutdowntimer->SetTimer(wsd->time);
                                        zoneserver_list.reminder->SetTimer(wsd->interval-1000);
                                        zoneserver_list.reminder->SetAtTrigger(wsd->interval);
                                        zoneserver_list.shutdowntimer->Start();
                                        zoneserver_list.reminder->Start();
                                }
                        }
                        break;
                }
                case ServerOP_ZoneShutdown: {
                        ServerZoneStateChange_struct* s = (ServerZoneStateChange_struct *) pack->pBuffer;
                        ZoneServer* zs = 0;
                        if (s->ZoneServerID != 0)
                                zs = zoneserver_list.FindByID(s->ZoneServerID);
                        else if (s->zoneid != 0)
                                zs = zoneserver_list.FindByName(database.GetZoneName(s->zoneid));
                        else
                                zoneserver_list.SendEmoteMessage(s->adminname, 0, 0, 0, "Error: SOP_ZoneShutdown: neither ID nor name specified");

                        if (zs == 0)
                                zoneserver_list.SendEmoteMessage(s->adminname, 0, 0, 0, "Error: SOP_ZoneShutdown: zoneserver not found");
                        else
                                zs->SendPacket(pack);
                        break;
                }
                case ServerOP_ZoneBootup: {
                        ServerZoneStateChange_struct* s = (ServerZoneStateChange_struct *) pack->pBuffer;
                        zoneserver_list.SOPZoneBootup(s->adminname, s->ZoneServerID, database.GetZoneName(s->zoneid), s->makestatic);
                        break;
                }
                case ServerOP_ZoneStatus: {
                        if (pack->size >= 1)
                                zoneserver_list.SendZoneStatus((char *) &pack->pBuffer[1], (int8) pack->pBuffer[0], this);
                        break;

                }
                case ServerOP_AcceptWorldEntrance: {
                        if(pack->size != sizeof(WorldToZone_Struct))
                                break;

                        WorldToZone_Struct* wtz = (WorldToZone_Struct*) pack->pBuffer;
                        Client* client = 0;
                        client = client_list.FindByAccountID(wtz->account_id);
                        if(client != 0)
                                client->Clearance(wtz->response);
                }
                case ServerOP_ZoneToZoneRequest: {
                //
                // solar: ZoneChange is received by the zone the player is in, then the
                // zone sends a ZTZ which ends up here.  This code then find the target
                // (ingress point) and boots it if needed, then sends the ZTZ to it.
                // The ingress server will decide wether the player can enter, then will
                // send back the ZTZ to here.  This packet is passed back to the egress
                // server, which will send a ZoneChange response back to the client
                // which can be an error, or a success, in which case the client will
                // disconnect, and their zone location will be saved when ~Client is
                // called, so it will be available when they ask to zone.
                //

                       
                        if(pack->size != sizeof(ZoneToZone_Struct))
                                break;
                        ZoneToZone_Struct* ztz = (ZoneToZone_Struct*) pack->pBuffer;
                        ClientListEntry* client = NULL;
                        if(WorldConfig::get()->UpdateStats)
                                client = client_list.FindCharacter(ztz->name);

                        zlog(WORLD__ZONE,"ZoneToZone request for %s current zone %d req zone %d\n",
                                ztz->name, ztz->current_zone_id, ztz->requested_zone_id);

                        if(GetZoneID() == ztz->current_zone_id && GetInstanceID() == ztz->current_instance_id)        // this is a request from the egress zone
                        {
                                zlog(WORLD__ZONE,"Processing ZTZ for egress from zone for client %s\n", ztz->name);

                                if
                                (
                                        ztz->admin < 80 &&
                                        ztz->ignorerestrictions < 2 &&
                                        zoneserver_list.IsZoneLocked(ztz->requested_zone_id)
                                )
                                {
                                        ztz->response = 0;
                                        SendPacket(pack);
                                        break;
                                }

                                ZoneServer *ingress_server = NULL;
                                if(ztz->requested_instance_id > 0)
                                {
                                        ingress_server = zoneserver_list.FindByInstanceID(ztz->requested_instance_id);
                                }
                                else
                                {
                                        ingress_server = zoneserver_list.FindByZoneID(ztz->requested_zone_id);

                                }

                                if(ingress_server)        // found a zone already running
                                {
                                        _log(WORLD__ZONE,"Found a zone already booted for %s\n", ztz->name);
                                        ztz->response = 1;
                                }
                                else        // need to boot one
                                {
                                        int server_id;
                                        if ((server_id = zoneserver_list.TriggerBootup(ztz->requested_zone_id, ztz->requested_instance_id))){
                                                _log(WORLD__ZONE,"Successfully booted a zone for %s\n", ztz->name);
                                                // bootup successful, ready to rock
                                                ztz->response = 1;
                                                ingress_server = zoneserver_list.FindByID(server_id);
                                        }
                                        else
                                        {
                                                _log(WORLD__ZONE_ERR,"FAILED to boot a zone for %s\n", ztz->name);
                                                // bootup failed, send back error code 0
                                                ztz->response = 0;
                                        }
                                }
                                if(ztz->response!=0 && client)
                                        client->LSZoneChange(ztz);
                                SendPacket(pack);        // send back to egress server
                                if(ingress_server)        // if we couldn't boot one, this is 0
                                {
                                        ingress_server->SendPacket(pack);        // inform target server
                                }
                        }
                        else        // this is response from the ingress server, route it back to the egress server
                        {
                                zlog(WORLD__ZONE,"Processing ZTZ for ingress to zone for client %s\n", ztz->name);
                                ZoneServer *egress_server = NULL;
                                if(ztz->current_instance_id > 0)
                                {
                                        egress_server = zoneserver_list.FindByInstanceID(ztz->current_instance_id);
                                }
                                else
                                {
                                        egress_server = zoneserver_list.FindByZoneID(ztz->current_zone_id);
                                }

                                if(egress_server)
                                {
                                        egress_server->SendPacket(pack);
                                }
                        }

                        break;
                }
                case ServerOP_ClientList: {
                        if (pack->size != sizeof(ServerClientList_Struct)) {
                                zlog(WORLD__ZONE_ERR,"Wrong size on ServerOP_ClientList. Got: %d, Expected: %d",pack->size,sizeof(ServerClientList_Struct));
                                break;
                        }
                        client_list.ClientUpdate(this, (ServerClientList_Struct*) pack->pBuffer);
                        break;
                }
                case ServerOP_ClientListKA: {
                        ServerClientListKeepAlive_Struct* sclka = (ServerClientListKeepAlive_Struct*) pack->pBuffer;
                        if (pack->size < 4 || pack->size != 4 + (4 * sclka->numupdates)) {
                                zlog(WORLD__ZONE_ERR,"Wrong size on ServerOP_ClientListKA. Got: %d, Expected: %d",pack->size, (4 + (4 * sclka->numupdates)));
                                break;
                        }
                        client_list.CLEKeepAlive(sclka->numupdates, sclka->wid);
                        break;
                }
                case ServerOP_Who: {
                        ServerWhoAll_Struct* whoall = (ServerWhoAll_Struct*) pack->pBuffer;
                        Who_All_Struct* whom = new Who_All_Struct;
                        memset(whom,0,sizeof(Who_All_Struct));
                        whom->gmlookup = whoall->gmlookup;
                        whom->lvllow = whoall->lvllow;
                        whom->lvlhigh = whoall->lvlhigh;
                        whom->wclass = whoall->wclass;
                        whom->wrace = whoall->wrace;
                        strcpy(whom->whom,whoall->whom);
                        client_list.SendWhoAll(whoall->fromid,whoall->from, whoall->admin, whom, this);
                        delete whom;
                        break;
                }
                case ServerOP_FriendsWho: {
                        ServerFriendsWho_Struct* FriendsWho = (ServerFriendsWho_Struct*) pack->pBuffer;
                        client_list.SendFriendsWho(FriendsWho, this);
                        break;
                }
                case ServerOP_LFGMatches: {
                        ServerLFGMatchesRequest_Struct* smrs = (ServerLFGMatchesRequest_Struct*) pack->pBuffer;
                        client_list.SendLFGMatches(smrs);
                        break;
                }
                case ServerOP_LFPMatches: {
                        ServerLFPMatchesRequest_Struct* smrs = (ServerLFPMatchesRequest_Struct*) pack->pBuffer;
                        LFPGroupList.SendLFPMatches(smrs);
                        break;
                }
                case ServerOP_LFPUpdate: {
                        ServerLFPUpdate_Struct* sus = (ServerLFPUpdate_Struct*) pack->pBuffer;       
                        if(sus->Action)
                                LFPGroupList.UpdateGroup(sus);
                        else
                                LFPGroupList.RemoveGroup(sus);
                        break;
                }
                case ServerOP_ZonePlayer: {
                        //ServerZonePlayer_Struct* szp = (ServerZonePlayer_Struct*) pack->pBuffer;
                        zoneserver_list.SendPacket(pack);
                        break;
                }
                case ServerOP_KickPlayer: {
                        zoneserver_list.SendPacket(pack);
                        break;
                }
                case ServerOP_KillPlayer: {
                        zoneserver_list.SendPacket(pack);
                        break;
                }
               
                //these opcodes get processed by the guild manager.
                case ServerOP_RefreshGuild:
                case ServerOP_DeleteGuild:
                case ServerOP_GuildCharRefresh:
                case ServerOP_GuildMemberUpdate: {
                        guild_mgr.ProcessZonePacket(pack);
                        break;
                }
               
                case ServerOP_FlagUpdate: {
                        ClientListEntry* cle = client_list.FindCLEByAccountID(*((int32*) pack->pBuffer));
                        if (cle)
                                cle->SetAdmin(*((sint16*) &pack->pBuffer[4]));
                        zoneserver_list.SendPacket(pack);
                        break;
                }
                case ServerOP_GMGoto: {
                        if (pack->size != sizeof(ServerGMGoto_Struct)) {
                                zlog(WORLD__ZONE_ERR,"Wrong size on ServerOP_GMGoto. Got: %d, Expected: %d",pack->size,sizeof(ServerGMGoto_Struct));
                                break;
                        }
                        ServerGMGoto_Struct* gmg = (ServerGMGoto_Struct*) pack->pBuffer;
                        ClientListEntry* cle = client_list.FindCharacter(gmg->gotoname);
                        if (cle != 0) {
                                if (cle->Server() == 0)
                                        this->SendEmoteMessage(gmg->myname, 0, 0, 13, "Error: Cannot identify %s's zoneserver.", gmg->gotoname);
                                else if (cle->Anon() == 1 && cle->Admin() > gmg->admin) // no snooping for anon GMs
                                        this->SendEmoteMessage(gmg->myname, 0, 0, 13, "Error: %s not found", gmg->gotoname);
                                else
                                        cle->Server()->SendPacket(pack);
                        }
                        else {
                                this->SendEmoteMessage(gmg->myname, 0, 0, 13, "Error: %s not found", gmg->gotoname);
                        }
                        break;
                }
                case ServerOP_Lock: {
                        if (pack->size != sizeof(ServerLock_Struct)) {
                                zlog(WORLD__ZONE_ERR,"Wrong size on ServerOP_Lock. Got: %d, Expected: %d",pack->size,sizeof(ServerLock_Struct));
                                break;
                        }
                        ServerLock_Struct* slock = (ServerLock_Struct*) pack->pBuffer;
                          if (slock->mode >= 1)
                                WorldConfig::LockWorld();
                        else
                                WorldConfig::UnlockWorld();
                        if (loginserver.Connected()) {
                                loginserver.SendStatus();
                                if (slock->mode >= 1)
                                        this->SendEmoteMessage(slock->myname, 0, 0, 13, "World locked");
                                else
                                        this->SendEmoteMessage(slock->myname, 0, 0, 13, "World unlocked");
                        }
                        else {
                                if (slock->mode >= 1)
                                        this->SendEmoteMessage(slock->myname, 0, 0, 13, "World locked, but login server not connected.");
                                else
                                        this->SendEmoteMessage(slock->myname, 0, 0, 13, "World unlocked, but login server not conencted.");
                        }
                        break;
                                                        }
                case ServerOP_Motd: {
                        if (pack->size != sizeof(ServerMotd_Struct)) {
                                zlog(WORLD__ZONE_ERR,"Wrong size on ServerOP_Motd. Got: %d, Expected: %d",pack->size,sizeof(ServerMotd_Struct));
                                break;
                        }
                        ServerMotd_Struct* smotd = (ServerMotd_Struct*) pack->pBuffer;
                        database.SetVariable("MOTD",smotd->motd);
                        //this->SendEmoteMessage(smotd->myname, 0, 0, 13, "Updated Motd.");
                        zoneserver_list.SendPacket(pack);
                        break;
                }
                case ServerOP_Uptime: {
                        if (pack->size != sizeof(ServerUptime_Struct)) {
                                zlog(WORLD__ZONE_ERR,"Wrong size on ServerOP_Uptime. Got: %d, Expected: %d",pack->size,sizeof(ServerUptime_Struct));
                                break;
                        }
                        ServerUptime_Struct* sus = (ServerUptime_Struct*) pack->pBuffer;
                        if (sus->zoneserverid == 0) {
                                ZSList::ShowUpTime(this, sus->adminname);
                        }
                        else {
                                ZoneServer* zs = zoneserver_list.FindByID(sus->zoneserverid);
                                if (zs)
                                        zs->SendPacket(pack);
                        }
                        break;
                                                          }
                case ServerOP_Petition: {
                        zoneserver_list.SendPacket(pack);
                        break;
                                                                }
                case ServerOP_GetWorldTime: {
                        zlog(WORLD__ZONE,"Broadcasting a world time update");
                        ServerPacket* pack = new ServerPacket;
                       
                        pack->opcode = ServerOP_SyncWorldTime;
                        pack->size = sizeof(eqTimeOfDay);
                        pack->pBuffer = new uchar[pack->size];
                        memset(pack->pBuffer, 0, pack->size);
                        eqTimeOfDay* tod = (eqTimeOfDay*) pack->pBuffer;
                        tod->start_eqtime=zoneserver_list.worldclock.getStartEQTime();
                        tod->start_realtime=zoneserver_list.worldclock.getStartRealTime();
                        SendPacket(pack);
                        delete pack;
                        break;
                                                                        }
                case ServerOP_SetWorldTime: {
                        zlog(WORLD__ZONE,"Received SetWorldTime");
                        eqTimeOfDay* newtime = (eqTimeOfDay*) pack->pBuffer;
                        zoneserver_list.worldclock.setEQTimeOfDay(newtime->start_eqtime, newtime->start_realtime);
                        zlog(WORLD__ZONE,"New time = %d-%d-%d %d:%d (%d)\n", newtime->start_eqtime.year, newtime->start_eqtime.month, (int)newtime->start_eqtime.day, (int)newtime->start_eqtime.hour, (int)newtime->start_eqtime.minute, (int)newtime->start_realtime);
                        zoneserver_list.worldclock.saveFile(WorldConfig::get()->EQTimeFile.c_str());
                        zoneserver_list.SendTimeSync();
                        break;
                }
                case ServerOP_IPLookup: {
                        if (pack->size < sizeof(ServerGenericWorldQuery_Struct)) {
                                zlog(WORLD__ZONE_ERR,"Wrong size on ServerOP_IPLookup. Got: %d, Expected (at least): %d",pack->size,sizeof(ServerGenericWorldQuery_Struct));
                                break;
                        }
                        ServerGenericWorldQuery_Struct* sgwq = (ServerGenericWorldQuery_Struct*) pack->pBuffer;
                        if (pack->size == sizeof(ServerGenericWorldQuery_Struct))
                                client_list.SendCLEList(sgwq->admin, sgwq->from, this);
                        else
                                client_list.SendCLEList(sgwq->admin, sgwq->from, this, sgwq->query);
                        break;
                }
                case ServerOP_LockZone: {
                        if (pack->size < sizeof(ServerLockZone_Struct)) {
                                zlog(WORLD__ZONE_ERR,"Wrong size on ServerOP_LockZone. Got: %d, Expected: %d",pack->size,sizeof(ServerLockZone_Struct));
                                break;
                        }
                        ServerLockZone_Struct* s = (ServerLockZone_Struct*) pack->pBuffer;
                        switch (s->op) {
                                case 0:
                                        zoneserver_list.ListLockedZones(s->adminname, this);
                                        break;
                                case 1:
                                        if (zoneserver_list.SetLockedZone(s->zoneID, true))
                                                zoneserver_list.SendEmoteMessage(0, 0, 80, 15, "Zone locked: %s", database.GetZoneName(s->zoneID));
                                        else
                                                this->SendEmoteMessageRaw(s->adminname, 0, 0, 0, "Failed to change lock");
                                        break;
                                case 2:
                                        if (zoneserver_list.SetLockedZone(s->zoneID, false))
                                                zoneserver_list.SendEmoteMessage(0, 0, 80, 15, "Zone unlocked: %s", database.GetZoneName(s->zoneID));
                                        else
                                                this->SendEmoteMessageRaw(s->adminname, 0, 0, 0, "Failed to change lock");
                                        break;
                        }
                        break;
                }
                case ServerOP_ItemStatus: {
                        zoneserver_list.SendPacket(pack);
                        break;
                }
                case ServerOP_OOCMute: {
                        zoneserver_list.SendPacket(pack);
                        break;
                }
                case ServerOP_Revoke: {
                        RevokeStruct* rev = (RevokeStruct*)pack->pBuffer;
                        ClientListEntry* cle = client_list.FindCharacter(rev->name);
                        if (cle != 0 && cle->Server() != 0)
                        {
                                cle->Server()->SendPacket(pack);
                        }
                        break;
                }
                case ServerOP_SpawnPlayerCorpse: {
                        SpawnPlayerCorpse_Struct* s = (SpawnPlayerCorpse_Struct*)pack->pBuffer;
                        ZoneServer* zs = zoneserver_list.FindByZoneID(s->zone_id);
                        if(zs) {
                                if (zs->SendPacket(pack)) {
                                        zlog(WORLD__ZONE,"Sent request to spawn player corpse id %i in zone %u.",s->player_corpse_id, s->zone_id);
                                }
                                else {
                                        zlog(WORLD__ZONE_ERR,"Could not send request to spawn player corpse id %i in zone %u.",s->player_corpse_id, s->zone_id);
                                }
                        }
                        break;
                }
            case ServerOP_Consent: {
                        // Message string id's likely to be used here are:
                        // CONSENT_YOURSELF = 399
                        // CONSENT_INVALID_NAME = 397
                        // TARGET_NOT_FOUND = 101
                        ZoneServer* zs;
                        ServerOP_Consent_Struct* s = (ServerOP_Consent_Struct*)pack->pBuffer;
                        ClientListEntry* cle = client_list.FindCharacter(s->grantname);
                        if(cle) {
                                if(cle->instance() != 0)
                                {
                                        zs = zoneserver_list.FindByInstanceID(cle->instance());
                                        if(zs) {
                                                if(zs->SendPacket(pack)) {
                                                        zlog(WORLD__ZONE, "Sent consent packet from player %s to player %s in zone %u.", s->ownername, s->grantname, cle->instance());
                                                }
                                                else {
                                                        zlog(WORLD__ZONE_ERR, "Unable to locate zone record for instance id %u in zoneserver list for ServerOP_Consent operation.", s->instance_id);
                                                }
                                        }
                                        else
                                        {
                                                delete pack;
                                                pack = new ServerPacket(ServerOP_Consent_Response, sizeof(ServerOP_Consent_Struct));
                                                ServerOP_Consent_Struct* scs = (ServerOP_Consent_Struct*)pack->pBuffer;
                                                strcpy(scs->grantname, s->grantname);
                                                strcpy(scs->ownername, s->ownername);
                                                scs->permission = s->permission;
                                                scs->zone_id = s->zone_id;
                                                scs->instance_id = s->instance_id;
                                                scs->message_string_id = 101;
                                                zs = zoneserver_list.FindByInstanceID(s->instance_id);
                                                if(zs) {
                                                        if(!zs->SendPacket(pack))
                                                                zlog(WORLD__ZONE_ERR, "Unable to send consent response back to player %s in instance %u.", s->ownername, zs->GetInstanceID());
                                                }
                                                else {
                                                        zlog(WORLD__ZONE_ERR, "Unable to locate zone record for instance id %u in zoneserver list for ServerOP_Consent_Response operation.", s->instance_id);
                                                }
                                        }
                                }
                                else
                                {
                                        zs = zoneserver_list.FindByZoneID(cle->zone());
                                        if(zs) {
                                                if(zs->SendPacket(pack)) {
                                                        zlog(WORLD__ZONE, "Sent consent packet from player %s to player %s in zone %u.", s->ownername, s->grantname, cle->zone());
                                                }
                                                else {
                                                        zlog(WORLD__ZONE_ERR, "Unable to locate zone record for zone id %u in zoneserver list for ServerOP_Consent operation.", s->zone_id);
                                                }
                                        }
                                        else {
                                                // send target not found back to requester
                                                delete pack;
                                                pack = new ServerPacket(ServerOP_Consent_Response, sizeof(ServerOP_Consent_Struct));
                                                ServerOP_Consent_Struct* scs = (ServerOP_Consent_Struct*)pack->pBuffer;
                                                strcpy(scs->grantname, s->grantname);
                                                strcpy(scs->ownername, s->ownername);
                                                scs->permission = s->permission;
                                                scs->zone_id = s->zone_id;
                                                scs->message_string_id = 101;
                                                zs = zoneserver_list.FindByZoneID(s->zone_id);
                                                if(zs) {
                                                        if(!zs->SendPacket(pack))
                                                                zlog(WORLD__ZONE_ERR, "Unable to send consent response back to player %s in zone %s.", s->ownername, zs->GetZoneName());
                                                }
                                                else {
                                                        zlog(WORLD__ZONE_ERR, "Unable to locate zone record for zone id %u in zoneserver list for ServerOP_Consent_Response operation.", s->zone_id);
                                                }
                                        }
                                }
                        }
                        else {
                                // send target not found back to requester
                                delete pack;
                                pack = new ServerPacket(ServerOP_Consent_Response, sizeof(ServerOP_Consent_Struct));
                                ServerOP_Consent_Struct* scs = (ServerOP_Consent_Struct*)pack->pBuffer;
                                strcpy(scs->grantname, s->grantname);
                                strcpy(scs->ownername, s->ownername);
                                scs->permission = s->permission;
                                scs->zone_id = s->zone_id;
                                scs->message_string_id = 397;
                                zs = zoneserver_list.FindByZoneID(s->zone_id);
                                if(zs) {
                                        if(!zs->SendPacket(pack))
                                                zlog(WORLD__ZONE_ERR, "Unable to send consent response back to player %s in zone %s.", s->ownername, zs->GetZoneName());
                                }
                                else {
                                        zlog(WORLD__ZONE_ERR, "Unable to locate zone record for zone id %u in zoneserver list for ServerOP_Consent_Response operation.", s->zone_id);
                                }
                        }
                        break;
                }
                case ServerOP_Consent_Response: {
                        // Message string id's likely to be used here are:
                        // CONSENT_YOURSELF = 399
                        // CONSENT_INVALID_NAME = 397
                        // TARGET_NOT_FOUND = 101
                        ServerOP_Consent_Struct* s = (ServerOP_Consent_Struct*)pack->pBuffer;
                        if(s->instance_id != 0)
                        {
                                ZoneServer* zs = zoneserver_list.FindByInstanceID(s->instance_id);
                                if(zs) {
                                        if(!zs->SendPacket(pack))
                                                zlog(WORLD__ZONE_ERR, "Unable to send consent response back to player %s in instance %u.", s->ownername, zs->GetInstanceID());
                                }
                                else {
                                        zlog(WORLD__ZONE_ERR, "Unable to locate zone record for instance id %u in zoneserver list for ServerOP_Consent_Response operation.", s->instance_id);
                                }
                        }
                        else
                        {
                                ZoneServer* zs = zoneserver_list.FindByZoneID(s->zone_id);
                                if(zs) {
                                        if(!zs->SendPacket(pack))
                                                zlog(WORLD__ZONE_ERR, "Unable to send consent response back to player %s in zone %s.", s->ownername, zs->GetZoneName());
                                }
                                else {
                                        zlog(WORLD__ZONE_ERR, "Unable to locate zone record for zone id %u in zoneserver list for ServerOP_Consent_Response operation.", s->zone_id);
                                }
                        }
                        break;
                }

                case ServerOP_InstanceUpdateTime :
                {
                        ServerInstanceUpdateTime_Struct *iut = (ServerInstanceUpdateTime_Struct*)pack->pBuffer;
                        ZoneServer *zm = zoneserver_list.FindByInstanceID(iut->instance_id);
                        if(zm)
                        {
                                zm->SendPacket(pack);
                        }
                        break;
                }
                case ServerOP_QGlobalUpdate:
                {
                        if(pack->size != sizeof(ServerQGlobalUpdate_Struct))
                {
                        break;
                }

                        zoneserver_list.SendPacket(pack);
                        break;
                }

                case ServerOP_QGlobalDelete:
                {
                        if(pack->size != sizeof(ServerQGlobalDelete_Struct))
                        {
                                break;
                        }

                        zoneserver_list.SendPacket(pack);
                        break;
                }

                case ServerOP_AdventureCreate:
                case ServerOP_AdventureAddPlayer:
                case ServerOP_AdventureDestroy:
                case ServerOP_AdventureUpdate:
                case ServerOP_AdventureCount:
                case ServerOP_AdventureFinish:
                case ServerOP_AdventureMessage:
                case ServerOP_DepopAllPlayersCorpses:
                case ServerOP_ReloadTitles:
                case ServerOP_SpawnStatusChange:
                case ServerOP_ReloadTasks:
                case ServerOP_UpdateSpawn:
                {
                        zoneserver_list.SendPacket(pack);
                        break;
                }
                default:
                {
                        zlog(WORLD__ZONE_ERR,"Unknown ServerOPcode from zone 0x%04x, size %d",pack->opcode,pack->size);
                        DumpPacket(pack->pBuffer, pack->size);
                        break;
                }
                }

                delete pack;
        }
        return true;
}

void ZoneServer::SendEmoteMessage(const char* to, int32 to_guilddbid, sint16 to_minstatus, int32 type, const char* message, ...) {
        if (!message)
                return;
        va_list argptr;
        char buffer[1024];

        va_start(argptr, message);
        vsnprintf(buffer, sizeof(buffer), message, argptr);
        va_end(argptr);
        SendEmoteMessageRaw(to, to_guilddbid, to_minstatus, type, buffer);
}

void ZoneServer::SendEmoteMessageRaw(const char* to, int32 to_guilddbid, sint16 to_minstatus, int32 type, const char* message) {
        if (!message)
                return;
        ServerPacket* pack = new ServerPacket;

        pack->opcode = ServerOP_EmoteMessage;
        pack->size = sizeof(ServerEmoteMessage_Struct)+strlen(message)+1;
        pack->pBuffer = new uchar[pack->size];
        memset(pack->pBuffer, 0, pack->size);
        ServerEmoteMessage_Struct* sem = (ServerEmoteMessage_Struct*) pack->pBuffer;
       
        if (to != 0) {
                strcpy((char *) sem->to, to);
        }
        else {
                sem->to[0] = 0;
        }

        sem->guilddbid = to_guilddbid;
        sem->minstatus = to_minstatus;
        sem->type = type;
        strcpy(&sem->message[0], message);
       
        pack->Deflate();
        SendPacket(pack);
        delete pack;
}

void ZoneServer::SendGroupIDs() {
        ServerPacket* pack = new ServerPacket(ServerOP_GroupIDReply, sizeof(ServerGroupIDReply_Struct));
        ServerGroupIDReply_Struct* sgi = (ServerGroupIDReply_Struct*)pack->pBuffer;
        zoneserver_list.NextGroupIDs(sgi->start, sgi->end);
        SendPacket(pack);
        delete pack;
}

void ZoneServer::ChangeWID(int32 iCharID, int32 iWID) {
        ServerPacket* pack = new ServerPacket(ServerOP_ChangeWID, sizeof(ServerChangeWID_Struct));
        ServerChangeWID_Struct* scw = (ServerChangeWID_Struct*) pack->pBuffer;
        scw->charid = iCharID;
        scw->newwid = iWID;
        zoneserver_list.SendPacket(pack);
        delete pack;
}


void ZoneServer::TriggerBootup(int32 iZoneID, int32 iInstanceID, const char* adminname, bool iMakeStatic) {
        BootingUp = true;
        zoneID = iZoneID;
        instanceID = iInstanceID;

        ServerPacket* pack = new ServerPacket(ServerOP_ZoneBootup, sizeof(ServerZoneStateChange_struct));
        ServerZoneStateChange_struct* s = (ServerZoneStateChange_struct *) pack->pBuffer;
        s->ZoneServerID = ID;
        if (adminname != 0)
                strcpy(s->adminname, adminname);
       
        if (iZoneID == 0)
                s->zoneid = this->GetZoneID();
        else
                s->zoneid = iZoneID;

        s->instanceid = iInstanceID;
        s->makestatic = iMakeStatic;
        SendPacket(pack);
        delete pack;
        LSBootUpdate(iZoneID, iInstanceID);
}

void ZoneServer::IncommingClient(Client* client) {
        BootingUp = true;
        ServerPacket* pack = new ServerPacket(ServerOP_ZoneIncClient, sizeof(ServerZoneIncommingClient_Struct));
        ServerZoneIncommingClient_Struct* s = (ServerZoneIncommingClient_Struct*) pack->pBuffer;
        s->zoneid = GetZoneID();
        s->instanceid = GetInstanceID();
        s->wid = client->GetWID();
        s->ip = client->GetIP();
        s->accid = client->GetAccountID();
        s->admin = client->GetAdmin();
        s->charid = client->GetCharID();
        if (client->GetCLE())
                s->tellsoff = client->GetCLE()->TellsOff();
        strn0cpy(s->charname, client->GetCharName(), sizeof(s->charname));
        strn0cpy(s->lskey, client->GetLSKey(), sizeof(s->lskey));
        SendPacket(pack);
        delete pack;
}

This was WORLD, COMMON will be on next post

Angelox 04-17-2010 11:12 AM

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


trevius 04-17-2010 08:35 PM

For the record, the dual LS code was originally from Secrets. I haven't done anything at all with the LS code yet :P

Angelox 04-17-2010 08:52 PM

Thanks - now I know why I couldn't find the post!

gaeorn 04-17-2010 10:29 PM

It's the first portion of the muiltiple login server thread. I renamed it since it no longer was limited to dual login servers.

rabbired1 02-28-2014 04:10 AM

makering..............


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

Powered by vBulletin®, Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.