svn -> git Migration

This commit is contained in:
KimLS
2013-02-16 16:14:39 -08:00
parent 88c9715fb0
commit da7347f76f
1174 changed files with 445622 additions and 0 deletions
+45
View File
@@ -0,0 +1,45 @@
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
SET(ucs_sources
chatchannel.cpp
clientlist.cpp
database.cpp
ucs.cpp
ucsconfig.cpp
worldserver.cpp
)
SET(ucs_headers
chatchannel.h
clientlist.h
database.h
ucsconfig.h
worldserver.h
)
ADD_EXECUTABLE(ucs ${ucs_sources} ${ucs_headers})
ADD_DEFINITIONS(-DUCS)
TARGET_LINK_LIBRARIES(ucs Common debug ${MySQL_LIBRARY_DEBUG} optimized ${MySQL_LIBRARY_RELEASE})
IF(MSVC)
SET_TARGET_PROPERTIES(ucs PROPERTIES LINK_FLAGS_RELEASE "/OPT:REF /OPT:ICF")
TARGET_LINK_LIBRARIES(ucs "Ws2_32.lib")
ENDIF(MSVC)
IF(MINGW)
TARGET_LINK_LIBRARIES(ucs "WS2_32")
ENDIF(MINGW)
IF(UNIX)
TARGET_LINK_LIBRARIES(ucs "dl")
TARGET_LINK_LIBRARIES(ucs "z")
TARGET_LINK_LIBRARIES(ucs "m")
TARGET_LINK_LIBRARIES(ucs "rt")
TARGET_LINK_LIBRARIES(ucs "pthread")
ADD_DEFINITIONS(-fPIC)
ENDIF(UNIX)
SET(EXECUTABLE_OUTPUT_PATH ../Bin)
+706
View File
@@ -0,0 +1,706 @@
/*
EQEMu: Everquest Server Emulator
Copyright (C) 2001-2008 EQEMu Development Team (http://eqemulator.net)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "chatchannel.h"
#include "clientlist.h"
#include "database.h"
#include "../common/MiscFunctions.h"
#include <cstdlib>
extern Database database;
extern uint32 ChatMessagesSent;
ChatChannel::ChatChannel(string inName, string inOwner, string inPassword, bool inPermanent, int inMinimumStatus) :
DeleteTimer(0) {
Name = inName;
Owner = inOwner;
Password = inPassword;
Permanent = inPermanent;
MinimumStatus = inMinimumStatus;
Moderated = false;
_log(UCS__TRACE, "New ChatChannel created: Name: [%s], Owner: [%s], Password: [%s], MinStatus: %i",
Name.c_str(), Owner.c_str(), Password.c_str(), MinimumStatus);
}
ChatChannel::~ChatChannel() {
LinkedListIterator<Client*> iterator(ClientsInChannel);
iterator.Reset();
while(iterator.MoreElements())
iterator.RemoveCurrent(false);
}
ChatChannel* ChatChannelList::CreateChannel(string Name, string Owner, string Password, bool Permanent, int MinimumStatus) {
ChatChannel *NewChannel = new ChatChannel(CapitaliseName(Name), Owner, Password, Permanent, MinimumStatus);
ChatChannels.Insert(NewChannel);
return NewChannel;
}
ChatChannel* ChatChannelList::FindChannel(string Name) {
string NormalisedName = CapitaliseName(Name);
LinkedListIterator<ChatChannel*> iterator(ChatChannels);
iterator.Reset();
while(iterator.MoreElements()) {
ChatChannel *CurrentChannel = iterator.GetData();
if(CurrentChannel && (CurrentChannel->Name == NormalisedName))
return iterator.GetData();
iterator.Advance();
}
return NULL;
}
void ChatChannelList::SendAllChannels(Client *c) {
if(!c) return;
if(!c->CanListAllChannels()) {
c->GeneralChannelMessage("You do not have permission to list all the channels.");
return;
}
c->GeneralChannelMessage("All current channels:");
int ChannelsInLine = 0;
LinkedListIterator<ChatChannel*> iterator(ChatChannels);
iterator.Reset();
string Message;
char CountString[10];
while(iterator.MoreElements()) {
ChatChannel *CurrentChannel = iterator.GetData();
if(!CurrentChannel || (CurrentChannel->GetMinStatus() > c->GetAccountStatus())) {
iterator.Advance();
continue;
}
if(ChannelsInLine > 0)
Message += ", ";
sprintf(CountString, "(%i)", CurrentChannel->MemberCount(c->GetAccountStatus()));
Message += CurrentChannel->GetName();
Message += CountString;
ChannelsInLine++;
if(ChannelsInLine == 6) {
c->GeneralChannelMessage(Message);
ChannelsInLine = 0;
Message.clear();
}
iterator.Advance();
}
if(ChannelsInLine > 0)
c->GeneralChannelMessage(Message);
}
void ChatChannelList::RemoveChannel(ChatChannel *Channel) {
_log(UCS__TRACE, "RemoveChannel(%s)", Channel->GetName().c_str());
LinkedListIterator<ChatChannel*> iterator(ChatChannels);
iterator.Reset();
while(iterator.MoreElements()) {
if(iterator.GetData() == Channel) {
iterator.RemoveCurrent();
return;
}
iterator.Advance();
}
}
void ChatChannelList::RemoveAllChannels() {
_log(UCS__TRACE, "RemoveAllChannels");
LinkedListIterator<ChatChannel*> iterator(ChatChannels);
iterator.Reset();
while(iterator.MoreElements())
iterator.RemoveCurrent();
}
int ChatChannel::MemberCount(int Status) {
int Count = 0;
LinkedListIterator<Client*> iterator(ClientsInChannel);
iterator.Reset();
while(iterator.MoreElements()) {
Client *ChannelClient = iterator.GetData();
if(ChannelClient && (!ChannelClient->GetHideMe() || (ChannelClient->GetAccountStatus() < Status)))
Count++;
iterator.Advance();
}
return Count;
}
void ChatChannel::SetPassword(string inPassword) {
Password = inPassword;
if(Permanent)
{
RemoveApostrophes(Password);
database.SetChannelPassword(Name, Password);
}
}
void ChatChannel::SetOwner(string inOwner) {
Owner = inOwner;
if(Permanent)
database.SetChannelOwner(Name, Owner);
}
void ChatChannel::AddClient(Client *c) {
if(!c) return;
DeleteTimer.Disable();
if(IsClientInChannel(c)) {
_log(UCS__ERROR, "Client %s already in channel %s", c->GetName().c_str(), GetName().c_str());
return;
}
bool HideMe = c->GetHideMe();
int AccountStatus = c->GetAccountStatus();
_log(UCS__TRACE, "Adding %s to channel %s", c->GetName().c_str(), Name.c_str());
LinkedListIterator<Client*> iterator(ClientsInChannel);
iterator.Reset();
while(iterator.MoreElements()) {
Client *CurrentClient = iterator.GetData();
if(CurrentClient && CurrentClient->IsAnnounceOn())
if(!HideMe || (CurrentClient->GetAccountStatus() > AccountStatus))
CurrentClient->AnnounceJoin(this, c);
iterator.Advance();
}
ClientsInChannel.Insert(c);
}
bool ChatChannel::RemoveClient(Client *c) {
if(!c) return false;
_log(UCS__TRACE, "RemoveClient %s from channel %s", c->GetName().c_str(), GetName().c_str());
bool HideMe = c->GetHideMe();
int AccountStatus = c->GetAccountStatus();
int PlayersInChannel = 0;
LinkedListIterator<Client*> iterator(ClientsInChannel);
iterator.Reset();
while(iterator.MoreElements()) {
Client *CurrentClient = iterator.GetData();
if(CurrentClient == c) {
iterator.RemoveCurrent(false);
}
else if(CurrentClient) {
PlayersInChannel++;
if(CurrentClient->IsAnnounceOn())
if(!HideMe || (CurrentClient->GetAccountStatus() > AccountStatus))
CurrentClient->AnnounceLeave(this, c);
iterator.Advance();
}
}
if((PlayersInChannel == 0) && !Permanent) {
if((Password.length() == 0) || (RuleI(Channels, DeleteTimer) == 0))
return false;
_log(UCS__TRACE, "Starting delete timer for empty password protected channel %s", Name.c_str());
DeleteTimer.Start(RuleI(Channels, DeleteTimer) * 60000);
}
return true;
}
void ChatChannel::SendOPList(Client *c) {
if(!c) return;
c->GeneralChannelMessage("Channel " + Name + " op-list: (Owner=" + Owner + ")");
list<string>::iterator Iterator;
for(Iterator = Moderators.begin(); Iterator != Moderators.end(); Iterator++)
c->GeneralChannelMessage((*Iterator));
}
void ChatChannel::SendChannelMembers(Client *c) {
if(!c) return;
char CountString[10];
sprintf(CountString, "(%i)", MemberCount(c->GetAccountStatus()));
string Message = "Channel " + GetName();
Message += CountString;
Message += " members:";
c->GeneralChannelMessage(Message);
int AccountStatus = c->GetAccountStatus();
Message.clear();
int MembersInLine = 0;
LinkedListIterator<Client*> iterator(ClientsInChannel);
iterator.Reset();
while(iterator.MoreElements()) {
Client *ChannelClient = iterator.GetData();
// Don't list hidden characters with status higher or equal than the character requesting the list.
//
if(!ChannelClient || (ChannelClient->GetHideMe() && (ChannelClient->GetAccountStatus() >= AccountStatus))) {
iterator.Advance();
continue;
}
if(MembersInLine > 0)
Message += ", ";
Message += ChannelClient->GetName();
MembersInLine++;
if(MembersInLine == 6) {
c->GeneralChannelMessage(Message);
MembersInLine = 0;
Message.clear();
}
iterator.Advance();
}
if(MembersInLine > 0)
c->GeneralChannelMessage(Message);
}
void ChatChannel::SendMessageToChannel(string Message, Client* Sender) {
if(!Sender) return;
ChatMessagesSent++;
LinkedListIterator<Client*> iterator(ClientsInChannel);
iterator.Reset();
while(iterator.MoreElements()) {
Client *ChannelClient = iterator.GetData();
if(ChannelClient)
{
_log(UCS__TRACE, "Sending message to %s from %s",
ChannelClient->GetName().c_str(), Sender->GetName().c_str());
ChannelClient->SendChannelMessage(Name, Message, Sender);
}
iterator.Advance();
}
}
void ChatChannel::SetModerated(bool inModerated) {
Moderated = inModerated;
LinkedListIterator<Client*> iterator(ClientsInChannel);
iterator.Reset();
while(iterator.MoreElements()) {
Client *ChannelClient = iterator.GetData();
if(ChannelClient) {
if(Moderated)
ChannelClient->GeneralChannelMessage("Channel " + Name + " is now moderated.");
else
ChannelClient->GeneralChannelMessage("Channel " + Name + " is no longer moderated.");
}
iterator.Advance();
}
}
bool ChatChannel::IsClientInChannel(Client *c) {
if(!c) return false;
LinkedListIterator<Client*> iterator(ClientsInChannel);
iterator.Reset();
while(iterator.MoreElements()) {
if(iterator.GetData() == c)
return true;
iterator.Advance();
}
return false;
}
ChatChannel *ChatChannelList::AddClientToChannel(string ChannelName, Client *c) {
if(!c) return NULL;
if((ChannelName.length() > 0) && (isdigit(ChannelName[0]))) {
c->GeneralChannelMessage("The channel name can not begin with a number.");
return NULL;
}
string NormalisedName, Password;
string::size_type Colon = ChannelName.find_first_of(":");
if(Colon == string::npos)
NormalisedName = CapitaliseName(ChannelName);
else {
NormalisedName = CapitaliseName(ChannelName.substr(0, Colon));
Password = ChannelName.substr(Colon + 1);
}
if((NormalisedName.length() > 64) || (Password.length() > 64)) {
c->GeneralChannelMessage("The channel name or password cannot exceed 64 characters.");
return NULL;
}
_log(UCS__TRACE, "AddClient to channel [%s] with password [%s]", NormalisedName.c_str(), Password.c_str());
ChatChannel *RequiredChannel = FindChannel(NormalisedName);
if(!RequiredChannel)
RequiredChannel = CreateChannel(NormalisedName, c->GetName(), Password, false, 0);
if(RequiredChannel->GetMinStatus() > c->GetAccountStatus()) {
string Message = "You do not have the required account status to join channel " + NormalisedName;
c->GeneralChannelMessage(Message);
return NULL;
}
if(RequiredChannel->IsClientInChannel(c))
return NULL;
if(RequiredChannel->IsInvitee(c->GetName())) {
RequiredChannel->AddClient(c);
RequiredChannel->RemoveInvitee(c->GetName());
return RequiredChannel;
}
if(RequiredChannel->CheckPassword(Password) || RequiredChannel->IsOwner(c->GetName()) || RequiredChannel->IsModerator(c->GetName()) ||
c->IsChannelAdmin()) {
RequiredChannel->AddClient(c);
return RequiredChannel;
}
c->GeneralChannelMessage("Incorrect password for channel " + (NormalisedName));
return NULL;
}
ChatChannel *ChatChannelList::RemoveClientFromChannel(string inChannelName, Client *c) {
if(!c) return NULL;
string ChannelName = inChannelName;
if((inChannelName.length() > 0) && isdigit(ChannelName[0]))
ChannelName = c->ChannelSlotName(atoi(inChannelName.c_str()));
ChatChannel *RequiredChannel = FindChannel(ChannelName);
if(!RequiredChannel)
return NULL;
// RemoveClient will return false if there is no-one left in the channel, and the channel is not permanent and has
// no password.
//
if(!RequiredChannel->RemoveClient(c))
RemoveChannel(RequiredChannel);
return RequiredChannel;
}
void ChatChannelList::Process() {
LinkedListIterator<ChatChannel*> iterator(ChatChannels);
iterator.Reset();
while(iterator.MoreElements()) {
ChatChannel *CurrentChannel = iterator.GetData();
if(CurrentChannel && CurrentChannel->ReadyToDelete()) {
_log(UCS__TRACE, "Empty temporary password protected channel %s being destroyed.",
CurrentChannel->GetName().c_str());
RemoveChannel(CurrentChannel);
}
iterator.Advance();
}
}
void ChatChannel::AddInvitee(string Invitee) {
if(!IsInvitee(Invitee)) {
Invitees.push_back(Invitee);
_log(UCS__TRACE, "Added %s as invitee to channel %s", Invitee.c_str(), Name.c_str());
}
}
void ChatChannel::RemoveInvitee(string Invitee) {
list<string>::iterator Iterator;
for(Iterator = Invitees.begin(); Iterator != Invitees.end(); Iterator++) {
if((*Iterator) == Invitee) {
Invitees.erase(Iterator);
_log(UCS__TRACE, "Removed %s as invitee to channel %s", Invitee.c_str(), Name.c_str());
return;
}
}
}
bool ChatChannel::IsInvitee(string Invitee) {
list<string>::iterator Iterator;
for(Iterator = Invitees.begin(); Iterator != Invitees.end(); Iterator++) {
if((*Iterator) == Invitee)
return true;
}
return false;
}
void ChatChannel::AddModerator(string Moderator) {
if(!IsModerator(Moderator)) {
Moderators.push_back(Moderator);
_log(UCS__TRACE, "Added %s as moderator to channel %s", Moderator.c_str(), Name.c_str());
}
}
void ChatChannel::RemoveModerator(string Moderator) {
list<string>::iterator Iterator;
for(Iterator = Moderators.begin(); Iterator != Moderators.end(); Iterator++) {
if((*Iterator) == Moderator) {
Moderators.erase(Iterator);
_log(UCS__TRACE, "Removed %s as moderator to channel %s", Moderator.c_str(), Name.c_str());
return;
}
}
}
bool ChatChannel::IsModerator(string Moderator) {
list<string>::iterator Iterator;
for(Iterator = Moderators.begin(); Iterator != Moderators.end(); Iterator++) {
if((*Iterator) == Moderator)
return true;
}
return false;
}
void ChatChannel::AddVoice(string inVoiced) {
if(!HasVoice(inVoiced)) {
Voiced.push_back(inVoiced);
_log(UCS__TRACE, "Added %s as voiced to channel %s", inVoiced.c_str(), Name.c_str());
}
}
void ChatChannel::RemoveVoice(string inVoiced) {
list<string>::iterator Iterator;
for(Iterator = Voiced.begin(); Iterator != Voiced.end(); Iterator++) {
if((*Iterator) == inVoiced) {
Voiced.erase(Iterator);
_log(UCS__TRACE, "Removed %s as voiced to channel %s", inVoiced.c_str(), Name.c_str());
return;
}
}
}
bool ChatChannel::HasVoice(string inVoiced) {
list<string>::iterator Iterator;
for(Iterator = Voiced.begin(); Iterator != Voiced.end(); Iterator++) {
if((*Iterator) == inVoiced)
return true;
}
return false;
}
string CapitaliseName(string inString) {
string NormalisedName = inString;
for(unsigned int i = 0; i < NormalisedName.length(); i++) {
if(i == 0)
NormalisedName[i] = toupper(NormalisedName[i]);
else
NormalisedName[i] = tolower(NormalisedName[i]);
}
return NormalisedName;
}
+92
View File
@@ -0,0 +1,92 @@
#ifndef CHATCHANNEL_H
#define CHATCHANNEL_H
//#include "clientlist.h"
#include "../common/linked_list.h"
#include "../common/timer.h"
#include <string>
#include <list>
using namespace std;
class Client;
class ChatChannel {
public:
ChatChannel(string inName, string inOwner, string inPassword, bool inPermanent, int inMinimumStatus = 0);
~ChatChannel();
void AddClient(Client *c);
bool RemoveClient(Client *c);
bool IsClientInChannel(Client *c);
int MemberCount(int Status);
string GetName() { return Name; }
void SendMessageToChannel(string Message, Client* Sender);
bool CheckPassword(string inPassword) { return ((Password.length() == 0) || (Password == inPassword)); }
void SetPassword(string inPassword);
bool IsOwner(string Name) { return (Owner == Name); }
void SetOwner(string inOwner);
void SendChannelMembers(Client *c);
int GetMinStatus() { return MinimumStatus; }
bool ReadyToDelete() { return DeleteTimer.Check(); }
void SendOPList(Client *c);
void AddInvitee(string Invitee);
void RemoveInvitee(string Invitee);
bool IsInvitee(string Invitee);
void AddModerator(string Moderator);
void RemoveModerator(string Modeerator);
bool IsModerator(string Moderator);
void AddVoice(string Voiced);
void RemoveVoice(string Voiced);
bool HasVoice(string Voiced);
inline bool IsModerated() { return Moderated; }
void SetModerated(bool inModerated);
friend class ChatChannelList;
private:
string Name;
string Owner;
string Password;
bool Permanent;
bool Moderated;
int MinimumStatus;
Timer DeleteTimer;
LinkedList<Client*> ClientsInChannel;
list<string> Moderators;
list<string> Invitees;
list<string> Voiced;
};
class ChatChannelList {
public:
ChatChannel* CreateChannel(string Name, string Owner, string Passwordi, bool Permanent, int MinimumStatus = 0);
ChatChannel* FindChannel(string Name);
ChatChannel* AddClientToChannel(string Channel, Client *c);
ChatChannel* RemoveClientFromChannel(string Channel, Client *c);
void RemoveClientFromAllChannels(Client *c);
void RemoveChannel(ChatChannel *Channel);
void RemoveAllChannels();
void SendAllChannels(Client *c);
void Process();
private:
LinkedList<ChatChannel*> ChatChannels;
};
string CapitaliseName(string inString);
#endif
+2409
View File
File diff suppressed because it is too large Load Diff
+195
View File
@@ -0,0 +1,195 @@
/*
EQEMu: Everquest Server Emulator
Copyright (C) 2001-2008 EQEMu Development Team (http://eqemulator.net)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef CHATSERVER_CLIENTLIST_H
#define CHATSERVER_CLIENTLIST_H
#include "../common/opcodemgr.h"
#include "../common/EQStreamType.h"
#include "../common/EQStreamFactory.h"
#include "../common/rulesys.h"
#include "chatchannel.h"
#include <list>
#include <vector>
#define MAX_JOINED_CHANNELS 10
enum { CommandJoin = 0, CommandLeaveAll, CommandLeave, CommandListAll, CommandList, CommandSet, CommandAnnounce, CommandSetOwner,
CommandOPList, CommandInvite, CommandGrant, CommandModerate, CommandVoice, CommandKick,
CommandPassword, CommandToggleInvites, CommandAFK, CommandUptime,
CommandGetHeaders, CommandGetBody, CommandMailTo, CommandSetMessageStatus, CommandSelectMailBox,
CommandSetMailForwarding, CommandBuddy, CommandIgnorePlayer,
CommandEndOfList };
struct CommandEntry {
const char *CommandString;
int CommandCode;
};
typedef enum { ConnectionTypeUnknown, ConnectionTypeCombined, ConnectionTypeMail, ConnectionTypeChat } ConnectionType;
static const CommandEntry Commands[] = {
{ "join", CommandJoin },
{ "leaveall", CommandLeaveAll },
{ "leave", CommandLeave },
{ "listall", CommandListAll },
{ "list", CommandList },
{ "set", CommandSet },
{ "announce", CommandAnnounce },
{ "setowner", CommandSetOwner },
{ "oplist", CommandOPList },
{ "invite", CommandInvite },
{ "grant", CommandGrant },
{ "moderate", CommandModerate },
{ "voice", CommandVoice },
{ "kick", CommandKick },
{ "password", CommandPassword },
{ "toggleinvites", CommandToggleInvites },
{ "afk", CommandAFK },
{ "uptime", CommandUptime },
{ "getheaders", CommandGetHeaders },
{ "getbody", CommandGetBody },
{ "mailto", CommandMailTo },
{ "setmessagestatus", CommandSetMessageStatus },
{ "selectmailbox", CommandSelectMailBox },
{ "setmailforwarding", CommandSetMailForwarding },
{ "buddy", CommandBuddy },
{ "ignoreplayer", CommandIgnorePlayer },
{ "", CommandEndOfList } };
struct CharacterEntry {
int CharID;
int Level;
string Name;
};
class Client {
public:
Client(EQStream* eqs);
~Client();
EQStream *ClientStream;
void AddCharacter(int CharID, const char *CharacterName, int Level);
void ClearCharacters() { Characters.clear(); }
void SendMailBoxes();
inline void QueuePacket(const EQApplicationPacket *p, bool ack_req=true) { ClientStream->QueuePacket(p, ack_req); }
string GetName() { if(Characters.size()) return Characters[0].Name; else return ""; }
void JoinChannels(string ChannelList);
void LeaveChannels(string ChannelList);
void LeaveAllChannels(bool SendUpdatedChannelList = true);
void AddToChannelList(ChatChannel *JoinedChannel);
void RemoveFromChannelList(ChatChannel *JoinedChannel);
void SendChannelMessage(string Message);
void SendChannelMessage(string ChannelName, string Message, Client *Sender);
void SendChannelMessageByNumber(string Message);
void SendChannelList();
void CloseConnection();
void ToggleAnnounce(string State);
bool IsAnnounceOn() { return (Announce == true); }
void AnnounceJoin(ChatChannel *Channel, Client *c);
void AnnounceLeave(ChatChannel *Channel, Client *c);
void GeneralChannelMessage(string Message);
void GeneralChannelMessage(const char *Characters);
void SetChannelPassword(string ChannelPassword);
void ProcessChannelList(string CommandString);
void AccountUpdate();
int ChannelCount();
inline void SetAccountID(int inAccountID) { AccountID = inAccountID; }
inline int GetAccountID() { return AccountID; }
inline void SetAccountStatus(int inStatus) { Status = inStatus; }
inline void SetHideMe(bool inHideMe) { HideMe = inHideMe; }
inline void SetKarma(uint32 inKarma) { TotalKarma = inKarma; }
inline int GetAccountStatus() { return Status; }
inline bool GetHideMe() { return HideMe; }
inline uint32 GetKarma() { return TotalKarma; }
void SetChannelOwner(string CommandString);
void OPList(string CommandString);
void ChannelInvite(string CommandString);
void ChannelGrantModerator(string CommandString);
void ChannelGrantVoice(string CommandString);
void ChannelKick(string CommandString);
void ChannelModerate(string CommandString);
string ChannelSlotName(int ChannelNumber);
void ToggleInvites();
bool InvitesAllowed() { return AllowInvites; }
bool IsRevoked() { return Revoked; }
void SetRevoked(bool r) { Revoked = r; }
inline bool IsChannelAdmin() { return (Status >= RuleI(Channels, RequiredStatusAdmin)); }
inline bool CanListAllChannels() { return (Status >= RuleI(Channels, RequiredStatusListAll)); }
void SendHelp();
inline bool GetForceDisconnect() { return ForceDisconnect; }
string MailBoxName();
int GetMailBoxNumber() { return CurrentMailBox; }
int GetMailBoxNumber(string CharacterName);
void SetConnectionType(char c);
ConnectionType GetConnectionType() { return TypeOfConnection; }
inline bool IsMailConnection() { return (TypeOfConnection == ConnectionTypeMail) || (TypeOfConnection == ConnectionTypeCombined); }
void SendNotification(int MailBoxNumber, string From, string Subject, int MessageID);
void ChangeMailBox(int NewMailBox);
inline void SetMailBox(int NewMailBox) { CurrentMailBox = NewMailBox; }
void SendFriends();
int GetCharID();
void SendUptime();
private:
unsigned int CurrentMailBox;
vector<CharacterEntry> Characters;
ChatChannel *JoinedChannels[MAX_JOINED_CHANNELS];
bool Announce;
int AccountID;
int Status;
bool HideMe;
bool AllowInvites;
bool Revoked;
//Anti Spam Stuff
Timer *AccountGrabUpdateTimer;
uint32 TotalKarma;
Timer *GlobalChatLimiterTimer; //60 seconds
int AttemptedMessages;
bool ForceDisconnect;
ConnectionType TypeOfConnection;
bool UnderfootOrLater;
};
class Clientlist {
public:
Clientlist(int MailPort);
void Process();
void CloseAllConnections();
Client *FindCharacter(string CharacterName);
void CheckForStaleConnections(Client *c);
Client *IsCharacterOnline(string CharacterName);
void ProcessOPMailCommand(Client *c, string CommandString);
private:
EQStreamFactory *chatsf;
list<Client*> ClientChatConnections;
OpcodeManager *ChatOpMgr;
};
#endif
+770
View File
@@ -0,0 +1,770 @@
/*
EQEMu: Everquest Server Emulator
Copyright (C) 2001-2008 EQEMu Development Team (http://eqemulator.net)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#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 _WINDOWS
#include <windows.h>
#define snprintf _snprintf
#define strncasecmp _strnicmp
#define strcasecmp _stricmp
#else
#include "../common/unix.h"
#include <netinet/in.h>
#endif
#include "database.h"
#include "../common/eq_packet_structs.h"
#include "../common/MiscFunctions.h"
#include "chatchannel.h"
extern Clientlist *CL;
extern string GetMailPrefix();
extern ChatChannelList *ChannelList;
extern uint32 MailMessagesSent;
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, uint32 port)
{
DBInitVars();
Connect(host, user, passwd, database, port);
}
bool Database::Connect(const char* host, const char* user, const char* passwd, const char* database, uint32 port)
{
uint32 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() {
}
void Database::HandleMysqlError(uint32 errnum) {
}
/*
Close the connection to the database
*/
Database::~Database()
{
}
void Database::GetAccountStatus(Client *c) {
char errbuf[MYSQL_ERRMSG_SIZE];
char* query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
if (!RunQuery(query,MakeAnyLenString(&query, "select `status`, `hideme`, `karma`, `revoked` from `account` where `id`='%i' limit 1",
c->GetAccountID()),errbuf,&result)){
_log(UCS__ERROR, "Unable to get account status for character %s, error %s", c->GetName().c_str(), errbuf);
safe_delete_array(query);
return;
}
_log(UCS__TRACE, "GetAccountStatus Query: %s", query);
safe_delete_array(query);
if(mysql_num_rows(result) != 1)
{
_log(UCS__ERROR, "Error in GetAccountStatus");
mysql_free_result(result);
return;
}
row = mysql_fetch_row(result);
c->SetAccountStatus(atoi(row[0]));
c->SetHideMe(atoi(row[1]) != 0);
c->SetKarma(atoi(row[2]));
c->SetRevoked((atoi(row[3])==1?true:false));
_log(UCS__TRACE, "Set account status to %i, hideme to %i and karma to %i for %s", c->GetAccountStatus(), c->GetHideMe(), c->GetKarma(), c->GetName().c_str());
mysql_free_result(result);
}
int Database::FindAccount(const char *CharacterName, Client *c) {
_log(UCS__TRACE, "FindAccount for character %s", CharacterName);
char errbuf[MYSQL_ERRMSG_SIZE];
char* query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
c->ClearCharacters();
if (!RunQuery(query,MakeAnyLenString(&query, "select `id`, `account_id`, `level` from `character_` where `name`='%s' limit 1",
CharacterName),errbuf,&result))
{
_log(UCS__ERROR, "FindAccount query failed: %s", query);
safe_delete_array(query);
return -1;
}
safe_delete_array(query);
if (mysql_num_rows(result) != 1)
{
_log(UCS__ERROR, "Bad result from query");
mysql_free_result(result);
return -1;
}
row = mysql_fetch_row(result);
c->AddCharacter(atoi(row[0]), CharacterName, atoi(row[2]));
int AccountID = atoi(row[1]);
mysql_free_result(result);
_log(UCS__TRACE, "Account ID for %s is %i", CharacterName, AccountID);
if (!RunQuery(query,MakeAnyLenString(&query, "select `id`, `name`, `level` from `character_` where `account_id`=%i and `name` !='%s'",
AccountID, CharacterName),errbuf,&result))
{
safe_delete_array(query);
return AccountID;
}
safe_delete_array(query);
for(unsigned int i = 0; i < mysql_num_rows(result); i++)
{
row = mysql_fetch_row(result);
c->AddCharacter(atoi(row[0]), row[1], atoi(row[2]));
}
mysql_free_result(result);
return AccountID;
}
bool Database::VerifyMailKey(string CharacterName, int IPAddress, string MailKey) {
char errbuf[MYSQL_ERRMSG_SIZE];
char* query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
if (!RunQuery(query,MakeAnyLenString(&query, "select `mailkey` from `character_` where `name`='%s' limit 1",
CharacterName.c_str()),errbuf,&result)){
safe_delete_array(query);
_log(UCS__ERROR, "Error retrieving mailkey from database: %s", errbuf);
return false;
}
safe_delete_array(query);
row = mysql_fetch_row(result);
// The key is the client's IP address (expressed as 8 hex digits) and an 8 hex digit random string generated
// by world.
//
char CombinedKey[17];
if(RuleB(Chat, EnableMailKeyIPVerification) == true)
sprintf(CombinedKey, "%08X%s", IPAddress, MailKey.c_str());
else
sprintf(CombinedKey, "%s", MailKey.c_str());
_log(UCS__TRACE, "DB key is [%s], Client key is [%s]", row[0], CombinedKey);
bool Valid = !strcmp(row[0], CombinedKey);
mysql_free_result(result);
return Valid;
}
int Database::FindCharacter(const char *CharacterName) {
char errbuf[MYSQL_ERRMSG_SIZE];
char* query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
char *SafeCharName = RemoveApostrophes(CharacterName);
if (!RunQuery(query,MakeAnyLenString(&query, "select `id` from `character_` where `name`='%s' limit 1",
SafeCharName),errbuf,&result)){
_log(UCS__ERROR, "FindCharacter failed. %s %s", query, errbuf);
safe_delete_array(query);
safe_delete_array(SafeCharName);
return -1;
}
safe_delete_array(query);
safe_delete_array(SafeCharName);
if (mysql_num_rows(result) != 1) {
_log(UCS__ERROR, "Bad result from FindCharacter query for character %s", CharacterName);
mysql_free_result(result);
return -1;
}
row = mysql_fetch_row(result);
int CharacterID = atoi(row[0]);
mysql_free_result(result);
return CharacterID;
}
bool Database::GetVariable(const char* varname, char* varvalue, uint16 varvalue_len) {
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`='%s'", varname), errbuf, &result)) {
_log(UCS__ERROR, "Unable to get message count from database. %s %s", query, errbuf);
safe_delete_array(query);
return false;
}
safe_delete_array(query);
if (mysql_num_rows(result) != 1) {
mysql_free_result(result);
return false;
}
row = mysql_fetch_row(result);
snprintf(varvalue, varvalue_len, "%s", row[0]);
mysql_free_result(result);
return true;
}
bool Database::LoadChatChannels() {
_log(UCS__INIT, "Loading chat channels from the database.");
char errbuf[MYSQL_ERRMSG_SIZE];
char* query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
if (!RunQuery(query,MakeAnyLenString(&query, "select `name`,`owner`,`password`, `minstatus` from `chatchannels`"),errbuf,&result)){
_log(UCS__ERROR, "Failed to load channels. %s %s", query, errbuf);
safe_delete_array(query);
return false;
}
safe_delete_array(query);
while((row = mysql_fetch_row(result))) {
string ChannelName = row[0];
string ChannelOwner = row[1];
string ChannelPassword = row[2];
ChannelList->CreateChannel(ChannelName, ChannelOwner, ChannelPassword, true, atoi(row[3]));
}
mysql_free_result(result);
return true;
}
void Database::SetChannelPassword(string ChannelName, string Password) {
_log(UCS__TRACE, "Database::SetChannelPassword(%s, %s)", ChannelName.c_str(), Password.c_str());
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
if(!RunQuery(query, MakeAnyLenString(&query, "UPDATE `chatchannels` set `password`='%s' where `name`='%s'", Password.c_str(),
ChannelName.c_str()), errbuf)) {
_log(UCS__ERROR, "Error updating password in database: %s, %s", query, errbuf);
}
safe_delete_array(query);
}
void Database::SetChannelOwner(string ChannelName, string Owner) {
_log(UCS__TRACE, "Database::SetChannelOwner(%s, %s)", ChannelName.c_str(), Owner.c_str());
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
if(!RunQuery(query, MakeAnyLenString(&query, "UPDATE `chatchannels` set `owner`='%s' where `name`='%s'", Owner.c_str(),
ChannelName.c_str()), errbuf)) {
_log(UCS__ERROR, "Error updating Owner in database: %s, %s", query, errbuf);
}
safe_delete_array(query);
}
void Database::SendHeaders(Client *c) {
int UnknownField2 = 25015275;
int UnknownField3 = 1;
int CharacterID = FindCharacter(c->MailBoxName().c_str());
_log(UCS__TRACE, "Sendheaders for %s, CharID is %i", c->MailBoxName().c_str(), CharacterID);
if(CharacterID <= 0)
return;
char errbuf[MYSQL_ERRMSG_SIZE];
char* query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
if (!RunQuery(query,MakeAnyLenString(&query, "select `msgid`,`timestamp`,`from`,`subject`, `status` from `mail` "
"where `charid`=%i", CharacterID),errbuf,&result)){
safe_delete_array(query);
return ;
}
safe_delete_array(query);
char Buf[100];
my_ulonglong NumRows = mysql_num_rows(result);
int HeaderCountPacketLength = 0;
sprintf(Buf, "%i", c->GetMailBoxNumber());
HeaderCountPacketLength += (strlen(Buf) + 1);
sprintf(Buf, "%i", UnknownField2);
HeaderCountPacketLength += (strlen(Buf) + 1);
sprintf(Buf, "%i", UnknownField3);
HeaderCountPacketLength += (strlen(Buf) + 1);
sprintf(Buf, "%i", NumRows);
HeaderCountPacketLength += (strlen(Buf) + 1);
EQApplicationPacket *outapp = new EQApplicationPacket(OP_MailHeaderCount, HeaderCountPacketLength);
char *PacketBuffer = (char *)outapp->pBuffer;
VARSTRUCT_ENCODE_INTSTRING(PacketBuffer, c->GetMailBoxNumber());
VARSTRUCT_ENCODE_INTSTRING(PacketBuffer, UnknownField2);
VARSTRUCT_ENCODE_INTSTRING(PacketBuffer, UnknownField3);
VARSTRUCT_ENCODE_INTSTRING(PacketBuffer, NumRows);
_pkt(UCS__PACKETS, outapp);
c->QueuePacket(outapp);
safe_delete(outapp);
int RowNum = 0;
while((row = mysql_fetch_row(result))) {
int HeaderPacketLength = 0;
sprintf(Buf, "%i", c->GetMailBoxNumber());
HeaderPacketLength = HeaderPacketLength + strlen(Buf) + 1;
sprintf(Buf, "%i", UnknownField2);
HeaderPacketLength = HeaderPacketLength + strlen(Buf) + 1;
sprintf(Buf, "%i", RowNum);
HeaderPacketLength = HeaderPacketLength + strlen(Buf) + 1;
HeaderPacketLength = HeaderPacketLength + strlen(row[0]) + 1;
HeaderPacketLength = HeaderPacketLength + strlen(row[1]) + 1;
HeaderPacketLength = HeaderPacketLength + strlen(row[4]) + 1;
HeaderPacketLength = HeaderPacketLength + GetMailPrefix().length() + strlen(row[2]) + 1;
HeaderPacketLength = HeaderPacketLength + strlen(row[3]) + 1;
outapp = new EQApplicationPacket(OP_MailHeader, HeaderPacketLength);
PacketBuffer = (char *)outapp->pBuffer;
VARSTRUCT_ENCODE_INTSTRING(PacketBuffer, c->GetMailBoxNumber());
VARSTRUCT_ENCODE_INTSTRING(PacketBuffer, UnknownField2);
VARSTRUCT_ENCODE_INTSTRING(PacketBuffer, RowNum);
VARSTRUCT_ENCODE_STRING(PacketBuffer, row[0]);
VARSTRUCT_ENCODE_STRING(PacketBuffer, row[1]);
VARSTRUCT_ENCODE_STRING(PacketBuffer, row[4]);
VARSTRUCT_ENCODE_STRING(PacketBuffer, GetMailPrefix().c_str()); PacketBuffer--;
VARSTRUCT_ENCODE_STRING(PacketBuffer, row[2]);
VARSTRUCT_ENCODE_STRING(PacketBuffer, row[3]);
_pkt(UCS__PACKETS, outapp);
c->QueuePacket(outapp);
safe_delete(outapp);
RowNum++;
}
mysql_free_result(result);
}
void Database::SendBody(Client *c, int MessageNumber) {
int CharacterID = FindCharacter(c->MailBoxName().c_str());
_log(UCS__TRACE, "SendBody: MsgID %i, to %s, CharID is %i", MessageNumber, c->MailBoxName().c_str(), CharacterID);
if(CharacterID <= 0)
return;
char errbuf[MYSQL_ERRMSG_SIZE];
char* query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
if (!RunQuery(query,MakeAnyLenString(&query, "select `msgid`, `body`, `to` from `mail` "
"where `charid`=%i and `msgid`=%i", CharacterID, MessageNumber), errbuf, &result)){
safe_delete_array(query);
return ;
}
safe_delete_array(query);
if (mysql_num_rows(result) != 1) {
mysql_free_result(result);
return;
}
row = mysql_fetch_row(result);
_log(UCS__TRACE, "Message: %i body (%i bytes)", MessageNumber, strlen(row[1]));
int PacketLength = 12 + strlen(row[0]) + strlen(row[1]) + strlen(row[2]);
EQApplicationPacket *outapp = new EQApplicationPacket(OP_MailSendBody,PacketLength);
char *PacketBuffer = (char *)outapp->pBuffer;
VARSTRUCT_ENCODE_INTSTRING(PacketBuffer, c->GetMailBoxNumber());
VARSTRUCT_ENCODE_STRING(PacketBuffer,row[0]);
VARSTRUCT_ENCODE_STRING(PacketBuffer,row[1]);
VARSTRUCT_ENCODE_STRING(PacketBuffer,"1");
VARSTRUCT_ENCODE_TYPE(uint8, PacketBuffer, 0);
VARSTRUCT_ENCODE_TYPE(uint8, PacketBuffer, 0x0a);
VARSTRUCT_ENCODE_STRING(PacketBuffer, "TO:"); PacketBuffer--;
VARSTRUCT_ENCODE_STRING(PacketBuffer, row[2]); PacketBuffer--; // Overwrite the null terminator
VARSTRUCT_ENCODE_TYPE(uint8, PacketBuffer, 0x0a);
mysql_free_result(result);
_pkt(UCS__PACKETS, outapp);
c->QueuePacket(outapp);
safe_delete(outapp);
}
bool Database::SendMail(string Recipient, string From, string Subject, string Body, string RecipientsString) {
int CharacterID;
string CharacterName;
//printf("Database::SendMail(%s, %s, %s)\n", Recipient.c_str(), From.c_str(), Subject.c_str());
string::size_type LastPeriod = Recipient.find_last_of(".");
if(LastPeriod == string::npos)
CharacterName = Recipient;
else
CharacterName = Recipient.substr(LastPeriod+1);
CharacterName[0] = toupper(CharacterName[0]);
for(unsigned int i = 1; i < CharacterName.length(); i++)
CharacterName[i] = tolower(CharacterName[i]);
CharacterID = FindCharacter(CharacterName.c_str());
_log(UCS__TRACE, "SendMail: CharacterID for recipient %s is %i", CharacterName.c_str(), CharacterID);
if(CharacterID <= 0) return false;
char errbuf[MYSQL_ERRMSG_SIZE];
char* query = 0;
char *EscSubject = new char[Subject.length() * 2 + 1];
char *EscBody = new char[Body.length() * 2 + 1];
DoEscapeString(EscSubject, Subject.c_str(), Subject.length());
DoEscapeString(EscBody, Body.c_str(), Body.length());
const char *MailQuery="INSERT INTO `mail` (`charid`, `timestamp`, `from`, `subject`, `body`, `to`, `status`) "
"VALUES ('%i', %i, '%s', '%s', '%s', '%s', %i)";
uint32 LastMsgID;
int Now = time(NULL); // time returns a 64 bit int on Windows at least, which vsnprintf doesn't like.
if(!RunQuery(query, MakeAnyLenString(&query, MailQuery, CharacterID, Now, From.c_str(), EscSubject, EscBody,
RecipientsString.c_str(), 1), errbuf, 0, 0, &LastMsgID)) {
_log(UCS__ERROR, "SendMail: Query %s failed with error %s", query, errbuf);
safe_delete_array(EscSubject);
safe_delete_array(EscBody);
safe_delete_array(query);
return false;
}
_log(UCS__TRACE, "MessageID %i generated, from %s, to %s", LastMsgID, From.c_str(), Recipient.c_str());
safe_delete_array(EscSubject);
safe_delete_array(EscBody);
safe_delete_array(query);
Client *c = CL->IsCharacterOnline(CharacterName);
if(c) {
string FQN = GetMailPrefix() + From;
c->SendNotification(c->GetMailBoxNumber(CharacterName), Subject, FQN, LastMsgID);
}
MailMessagesSent++;
return true;
}
void Database::SetMessageStatus(int MessageNumber, int Status) {
_log(UCS__TRACE, "SetMessageStatus %i %i", MessageNumber, Status);
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
if(Status == 0)
RunQuery(query, MakeAnyLenString(&query, "delete from `mail` where `msgid`=%i", MessageNumber), errbuf);
else if (!RunQuery(query, MakeAnyLenString(&query, "update `mail` set `status`=%i where `msgid`=%i", Status, MessageNumber), errbuf)) {
_log(UCS__ERROR, "Error updating status %s, %s", query, errbuf);
}
safe_delete_array(query);
}
void Database::ExpireMail() {
_log(UCS__INIT, "Expiring mail...");
char errbuf[MYSQL_ERRMSG_SIZE];
char* query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
uint32 AffectedRows;
if (!RunQuery(query,MakeAnyLenString(&query, "select COUNT(*) from `mail` "),errbuf,&result)){
_log(UCS__ERROR, "Unable to get message count from database. %s %s", query, errbuf);
safe_delete_array(query);
return ;
}
safe_delete_array(query);
row = mysql_fetch_row(result);
_log(UCS__INIT, "There are %s messages in the database.", row[0]);
mysql_free_result(result);
// Expire Trash
if(RuleI(Mail, ExpireTrash) >= 0) {
if(RunQuery(query, MakeAnyLenString(&query, "delete from `mail` where `status`=4 and `timestamp` < %i",
time(NULL) - RuleI(Mail, ExpireTrash)), errbuf, 0, &AffectedRows)) {
_log(UCS__INIT, "Expired %i trash messages.", AffectedRows);
}
else {
_log(UCS__ERROR, "Error expiring trash messages, %s %s", query, errbuf);
}
safe_delete_array(query);
}
// Expire Read
if(RuleI(Mail, ExpireRead) >= 0) {
if(RunQuery(query, MakeAnyLenString(&query, "delete from `mail` where `status`=3 and `timestamp` < %i",
time(NULL) - RuleI(Mail, ExpireRead)), errbuf, 0, &AffectedRows)) {
_log(UCS__INIT, "Expired %i read messages.", AffectedRows);
}
else {
_log(UCS__ERROR, "Error expiring read messages, %s %s", query, errbuf);
}
safe_delete_array(query);
}
// Expire Unread
if(RuleI(Mail, ExpireUnread) >= 0) {
if(RunQuery(query, MakeAnyLenString(&query, "delete from `mail` where `status`=1 and `timestamp` < %i",
time(NULL) - RuleI(Mail, ExpireUnread)), errbuf, 0, &AffectedRows)) {
_log(UCS__INIT, "Expired %i unread messages.", AffectedRows);
}
else {
_log(UCS__ERROR, "Error expiring unread messages, %s %s", query, errbuf);
}
safe_delete_array(query);
}
}
void Database::AddFriendOrIgnore(int CharID, int Type, string Name) {
const char *FriendsQuery="INSERT INTO `friends` (`charid`, `type`, `name`) VALUES ('%i', %i, '%s')";
char errbuf[MYSQL_ERRMSG_SIZE];
char* query = 0;
if(!RunQuery(query, MakeAnyLenString(&query, FriendsQuery, CharID, Type, CapitaliseName(Name).c_str()), errbuf, 0, 0))
_log(UCS__ERROR, "Error adding friend/ignore, query was %s : %s", query, errbuf);
else
_log(UCS__TRACE, "Wrote Friend/Ignore entry for charid %i, type %i, name %s to database.",
CharID, Type, Name.c_str());
safe_delete_array(query);
}
void Database::RemoveFriendOrIgnore(int CharID, int Type, string Name) {
const char *FriendsQuery="DELETE FROM `friends` WHERE `charid`=%i AND `type`=%i and `name`='%s'";
char errbuf[MYSQL_ERRMSG_SIZE];
char* query = 0;
if(!RunQuery(query, MakeAnyLenString(&query, FriendsQuery, CharID, Type, CapitaliseName(Name).c_str()), errbuf, 0, 0))
_log(UCS__ERROR, "Error removing friend/ignore, query was %s", query);
else
_log(UCS__TRACE, "Removed Friend/Ignore entry for charid %i, type %i, name %s from database.",
CharID, Type, Name.c_str());
safe_delete_array(query);
}
void Database::GetFriendsAndIgnore(int CharID, vector<string> &Friends, vector<string> &Ignorees) {
char errbuf[MYSQL_ERRMSG_SIZE];
char* query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
const char *FriendsQuery="select `type`, `name` from `friends` WHERE `charid`=%i";
if (!RunQuery(query,MakeAnyLenString(&query, FriendsQuery, CharID),errbuf,&result)){
_log(UCS__ERROR, "GetFriendsAndIgnore query error %s, %s", query, errbuf);
safe_delete_array(query);
return ;
}
safe_delete_array(query);
while((row = mysql_fetch_row(result))) {
string Name = row[1];
if(atoi(row[0]) == 0)
{
Ignorees.push_back(Name);
_log(UCS__TRACE, "Added Ignoree from DB %s", Name.c_str());
}
else
{
Friends.push_back(Name);
_log(UCS__TRACE, "Added Friend from DB %s", Name.c_str());
}
}
mysql_free_result(result);
return;
}
+73
View File
@@ -0,0 +1,73 @@
/*
EQEMu: Everquest Server Emulator
Copyright (C) 2001-2008 EQEMu Development Team (http://eqemulator.net)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef CHATSERVER_DATABASE_H
#define CHATSERVER_DATABASE_H
#define AUTHENTICATION_TIMEOUT 60
#define INVALID_ID 0xFFFFFFFF
#include "../common/debug.h"
#include "../common/types.h"
#include "../common/dbcore.h"
#include "../common/linked_list.h"
#include "clientlist.h"
#include <string>
#include <vector>
#include <map>
using namespace std;
//atoi is not uint32 or uint32 safe!!!!
#define atoul(str) strtoul(str, NULL, 10)
class Database : public DBcore {
public:
Database();
Database(const char* host, const char* user, const char* passwd, const char* database,uint32 port);
bool Connect(const char* host, const char* user, const char* passwd, const char* database,uint32 port);
~Database();
int FindAccount(const char *CharacterName, Client *c);
int FindCharacter(const char *CharacterName);
bool VerifyMailKey(string CharacterName, int IPAddress, string MailKey);
bool GetVariable(const char* varname, char* varvalue, uint16 varvalue_len);
bool LoadChatChannels();
void GetAccountStatus(Client *c);
void SetChannelPassword(string ChannelName, string Password);
void SetChannelOwner(string ChannelName, string Owner);
void SendHeaders(Client *c);
void SendBody(Client *c, int MessageNumber);
bool SendMail(string Recipient, string From, string Subject, string Body, string RecipientsString);
void SetMessageStatus(int MessageNumber, int Status);
void ExpireMail();
void AddFriendOrIgnore(int CharID, int Type, string Name);
void RemoveFriendOrIgnore(int CharID, int Type, string Name);
void GetFriendsAndIgnore(int CharID, vector<string> &Friends, vector<string> &Ignorees);
protected:
void HandleMysqlError(uint32 errnum);
private:
void DBInitVars();
};
#endif
+192
View File
@@ -0,0 +1,192 @@
/*
EQEMu: Everquest Server Emulator
Copyright (C) 2001-2008 EQEMu Development Team (http://eqemulator.net)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "../common/debug.h"
#include "clientlist.h"
#include "../common/opcodemgr.h"
#include "../common/EQStreamFactory.h"
#include "../common/rulesys.h"
#include "../common/servertalk.h"
#include "../common/platform.h"
#include "../common/crash.h"
#include "database.h"
#include "ucsconfig.h"
#include "chatchannel.h"
#include "worldserver.h"
#include <list>
#include <signal.h>
volatile bool RunLoops = true;
uint32 MailMessagesSent = 0;
uint32 ChatMessagesSent = 0;
TimeoutManager timeout_manager;
Clientlist *CL;
ChatChannelList *ChannelList;
Database database;
string WorldShortName;
RuleManager *rules = new RuleManager();
const ucsconfig *Config;
WorldServer *worldserver = 0;
void CatchSignal(int sig_num) {
RunLoops = false;
if(worldserver)
worldserver->Disconnect();
}
string GetMailPrefix() {
return "SOE.EQ." + WorldShortName + ".";
}
int main() {
RegisterExecutablePlatform(ExePlatformUCS);
set_exception_handler();
// Check every minute for unused channels we can delete
//
Timer ChannelListProcessTimer(60000);
Timer InterserverTimer(INTERSERVER_TIMER); // does auto-reconnect
_log(UCS__INIT, "Starting EQEmu Universal Chat Server.");
if (!ucsconfig::LoadConfig()) {
_log(UCS__INIT, "Loading server configuration failed.");
return(1);
}
Config = ucsconfig::get();
if(!load_log_settings(Config->LogSettingsFile.c_str()))
_log(UCS__INIT, "Warning: Unable to read %s", Config->LogSettingsFile.c_str());
else
_log(UCS__INIT, "Log settings loaded from %s", Config->LogSettingsFile.c_str());
WorldShortName = Config->ShortName;
_log(UCS__INIT, "Connecting to MySQL...");
if (!database.Connect(
Config->DatabaseHost.c_str(),
Config->DatabaseUsername.c_str(),
Config->DatabasePassword.c_str(),
Config->DatabaseDB.c_str(),
Config->DatabasePort)) {
_log(WORLD__INIT_ERR, "Cannot continue without a database connection.");
return(1);
}
char tmp[64];
if (database.GetVariable("RuleSet", tmp, sizeof(tmp)-1)) {
_log(WORLD__INIT, "Loading rule set '%s'", tmp);
if(!rules->LoadRules(&database, tmp)) {
_log(UCS__ERROR, "Failed to load ruleset '%s', falling back to defaults.", tmp);
}
} else {
if(!rules->LoadRules(&database, "default")) {
_log(UCS__INIT, "No rule set configured, using default rules");
} else {
_log(UCS__INIT, "Loaded default rule set 'default'", tmp);
}
}
database.ExpireMail();
if(Config->ChatPort != Config->MailPort)
{
_log(UCS__ERROR, "MailPort and CharPort must be the same in eqemu_config.xml for UCS.");
exit(1);
}
CL = new Clientlist(Config->ChatPort);
ChannelList = new ChatChannelList();
database.LoadChatChannels();
if (signal(SIGINT, CatchSignal) == SIG_ERR) {
_log(UCS__ERROR, "Could not set signal handler");
return 0;
}
if (signal(SIGTERM, CatchSignal) == SIG_ERR) {
_log(UCS__ERROR, "Could not set signal handler");
return 0;
}
worldserver = new WorldServer;
worldserver->Connect();
while(RunLoops) {
Timer::SetCurrentTime();
CL->Process();
if(ChannelListProcessTimer.Check())
ChannelList->Process();
if (InterserverTimer.Check()) {
if (worldserver->TryReconnect() && (!worldserver->Connected()))
worldserver->AsyncConnect();
}
worldserver->Process();
timeout_manager.CheckTimeouts();
Sleep(100);
}
ChannelList->RemoveAllChannels();
CL->CloseAllConnections();
}
void UpdateWindowTitle(char* iNewTitle) {
#ifdef _WINDOWS
char tmp[500];
if (iNewTitle) {
snprintf(tmp, sizeof(tmp), "UCS: %s", iNewTitle);
}
else {
snprintf(tmp, sizeof(tmp), "UCS");
}
SetConsoleTitle(tmp);
#endif
}
+29
View File
@@ -0,0 +1,29 @@
/*
EQEMu: Everquest Server Emulator
Copyright (C) 2001-2008 EQEMu Development Team (http://eqemulator.net)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "../common/debug.h"
#include "ucsconfig.h"
ucsconfig *ucsconfig::_chat_config = NULL;
string ucsconfig::GetByName(const string &var_name) const {
return(EQEmuConfig::GetByName(var_name));
}
+56
View File
@@ -0,0 +1,56 @@
/*
EQEMu: Everquest Server Emulator
Copyright (C) 2001-2008 EQEMu Development Team (http://eqemulator.net)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __ucsconfig_H
#define __ucsconfig_H
#include "../common/EQEmuConfig.h"
class ucsconfig : public EQEmuConfig {
public:
virtual string GetByName(const string &var_name) const;
private:
static ucsconfig *_chat_config;
public:
// Produce a const singleton
static const ucsconfig *get() {
if (_chat_config == NULL)
LoadConfig();
return(_chat_config);
}
// Load the config
static bool LoadConfig() {
if (_chat_config != NULL)
delete _chat_config;
_chat_config=new ucsconfig;
_config=_chat_config;
return _config->ParseFile(EQEmuConfig::ConfigFile.c_str(),"server");
}
};
#endif
+134
View File
@@ -0,0 +1,134 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "../common/debug.h"
#include <iostream>
using namespace std;
#include <string.h>
#include <stdio.h>
#include <iomanip>
#include <time.h>
#include <stdlib.h>
#include <stdarg.h>
#include "../common/servertalk.h"
#include "worldserver.h"
#include "clientlist.h"
#include "ucsconfig.h"
#include "database.h"
#include "../common/packet_functions.h"
#include "../common/md5.h"
extern WorldServer worldserver;
extern Clientlist *CL;
extern const ucsconfig *Config;
extern Database database;
void ProcessMailTo(Client *c, string from, string subject, string message);
WorldServer::WorldServer()
: WorldConnection(EmuTCPConnection::packetModeUCS, Config->SharedKey.c_str())
{
pTryReconnect = true;
}
WorldServer::~WorldServer()
{
}
void WorldServer::OnConnected()
{
_log(UCS__INIT, "Connected to World.");
WorldConnection::OnConnected();
}
void WorldServer::Process()
{
WorldConnection::Process();
if (!Connected())
return;
ServerPacket *pack = 0;
while((pack = tcpc.PopPacket()))
{
_log(UCS__TRACE, "Received Opcode: %4X", pack->opcode);
switch(pack->opcode)
{
case 0: {
break;
}
case ServerOP_KeepAlive:
{
break;
}
case ServerOP_UCSMessage:
{
char *Buffer = (char *)pack->pBuffer;
char *From = new char[strlen(Buffer) + 1];
VARSTRUCT_DECODE_STRING(From, Buffer);
string Message = Buffer;
_log(UCS__TRACE, "Player: %s, Sent Message: %s", From, Message.c_str());
Client *c = CL->FindCharacter(From);
safe_delete_array(From);
if(Message.length() < 2)
break;
if(!c)
{
_log(UCS__TRACE, "Client not found.");
break;
}
if(Message[0] == ';')
{
c->SendChannelMessageByNumber(Message.substr(1, string::npos));
}
else if(Message[0] == '[')
{
CL->ProcessOPMailCommand(c, Message.substr(1, string::npos));
}
break;
}
case ServerOP_UCSMailMessage:
{
ServerMailMessageHeader_Struct *mail = (ServerMailMessageHeader_Struct*)pack->pBuffer;
database.SendMail(string("SOE.EQ.") + Config->ShortName + string(".") + string(mail->to),
string(mail->from),
mail->subject,
mail->message,
string());
break;
}
}
}
safe_delete(pack);
return;
}
+35
View File
@@ -0,0 +1,35 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef WORLDSERVER_H
#define WORLDSERVER_H
#include "../common/worldconn.h"
#include "../common/eq_packet_structs.h"
class WorldServer : public WorldConnection
{
public:
WorldServer();
virtual ~WorldServer();
virtual void Process();
private:
virtual void OnConnected();
};
#endif