summaryrefslogtreecommitdiff
path: root/src/chat-server
diff options
context:
space:
mode:
Diffstat (limited to 'src/chat-server')
-rw-r--r--src/chat-server/chatchannel.cpp117
-rw-r--r--src/chat-server/chatchannel.hpp121
-rw-r--r--src/chat-server/chatchannelmanager.cpp187
-rw-r--r--src/chat-server/chatchannelmanager.hpp159
-rw-r--r--src/chat-server/chathandler.cpp529
-rw-r--r--src/chat-server/chathandler.hpp99
6 files changed, 1212 insertions, 0 deletions
diff --git a/src/chat-server/chatchannel.cpp b/src/chat-server/chatchannel.cpp
new file mode 100644
index 00000000..9f2bd607
--- /dev/null
+++ b/src/chat-server/chatchannel.cpp
@@ -0,0 +1,117 @@
+/*
+ * The Mana World Server
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; 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 The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#include "chat-server/chatchannel.hpp"
+
+ChatChannel::ChatChannel(const std::string &channelName,
+ const std::string &channelAnnouncement = "None",
+ const std::string &channelPassword = "None"):
+ mChannelName(channelName),
+ mChannelAnnouncement(channelAnnouncement),
+ mChannelPassword(channelPassword)
+{
+ if (channelAnnouncement == "")
+ mChannelAnnouncement = "None";
+ if (channelPassword == "")
+ mChannelPassword = "None";
+ mRegisteredUsers.clear();
+}
+
+ChatChannel::~ChatChannel()
+{
+ mRegisteredUsers.clear();
+}
+
+
+const std::string&
+ChatChannel::getName() const
+{
+ return mChannelName;
+}
+
+const std::string&
+ChatChannel::getAnnouncement() const
+{
+ return mChannelAnnouncement;
+}
+
+const std::string&
+ChatChannel::getPassword() const
+{
+ return mChannelPassword;
+}
+
+void
+ChatChannel::setName(const std::string &channelName)
+{
+ mChannelName = channelName;
+}
+
+void
+ChatChannel::setAnnouncement(const std::string &channelAnnouncement)
+{
+ if (channelAnnouncement == "")
+ mChannelAnnouncement = "None";
+ else
+ mChannelAnnouncement = channelAnnouncement;
+}
+
+void
+ChatChannel::setPassword(const std::string &channelPassword)
+{
+ if (channelPassword == "")
+ mChannelPassword = "None";
+ else
+ mChannelPassword = channelPassword;
+}
+
+ChatChannel::ChannelUsers const &ChatChannel::getUserList() const
+{
+ return mRegisteredUsers;
+}
+
+
+bool ChatChannel::addUserInChannel(std::string const &user)
+{
+ // Check if the user already exists in the channel
+ ChannelUsers::const_iterator i = mRegisteredUsers.begin(),
+ i_end = mRegisteredUsers.end();
+ if (std::find(i, i_end, user) == i_end) return false;
+ mRegisteredUsers.push_back(user);
+ return true;
+}
+
+
+bool ChatChannel::removeUserFromChannel(std::string const &user)
+{
+ ChannelUsers::iterator i_end = mRegisteredUsers.end(),
+ i = std::find(mRegisteredUsers.begin(), i_end, user);
+ if (i == i_end) return false;
+ mRegisteredUsers.erase(i);
+ return true;
+}
+
+void ChatChannel::removeEveryUsersFromChannel()
+{
+ mRegisteredUsers.clear();
+}
diff --git a/src/chat-server/chatchannel.hpp b/src/chat-server/chatchannel.hpp
new file mode 100644
index 00000000..29a0734e
--- /dev/null
+++ b/src/chat-server/chatchannel.hpp
@@ -0,0 +1,121 @@
+/*
+ * The Mana World Server
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; 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 The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#ifndef _TMWSERV_CHATCHANNEL_H_
+#define _TMWSERV_CHATCHANNEL_H_
+
+#include <string>
+#include <vector>
+
+#include "being.h"
+
+class ChatChannel {
+ public:
+ typedef std::vector< std::string > ChannelUsers;
+
+ /**
+ * Constructors
+ */
+ ChatChannel(const std::string &channelName,
+ const std::string &channelAnnouncement,
+ const std::string &channelPassword);
+
+ /**
+ * Destructor
+ */
+ ~ChatChannel();
+
+ /**
+ * Get the name of the channel
+ */
+ const std::string& getName() const;
+
+ /**
+ * Get the Announcement string of the channel
+ */
+ const std::string& getAnnouncement() const;
+
+ /**
+ * Get the password of the channel
+ */
+ const std::string& getPassword() const;
+
+ /**
+ * Set the name of the channel
+ */
+ void setName(const std::string &channelName);
+
+ /**
+ * Set the Announcement string of the channel
+ */
+ void setAnnouncement(const std::string &channelAnnouncement);
+
+ /**
+ * Set the password of the channel
+ */
+ void setPassword(const std::string &channelPassword);
+
+ /**
+ * Get the list of the users registered in the channel
+ */
+ ChannelUsers const &getUserList() const;
+
+ /**
+ * Add a user in the channel
+ */
+ bool addUserInChannel(std::string const &);
+
+ /**
+ * Remove a user from the channel.
+ */
+ bool removeUserFromChannel(std::string const &);
+
+ /**
+ * Empties a channel from its users (admin included).
+ */
+ void removeEveryUsersFromChannel();
+
+ private:
+ /**
+ * The Channel's name.
+ */
+ std::string mChannelName;
+
+ /**
+ * The Channel's announcement.
+ */
+ std::string mChannelAnnouncement;
+
+ /**
+ * The Channel's password.
+ */
+ std::string mChannelPassword;
+
+ /**
+ * The registered user list
+ */
+ ChannelUsers mRegisteredUsers;
+
+};
+
+#endif
diff --git a/src/chat-server/chatchannelmanager.cpp b/src/chat-server/chatchannelmanager.cpp
new file mode 100644
index 00000000..9944681e
--- /dev/null
+++ b/src/chat-server/chatchannelmanager.cpp
@@ -0,0 +1,187 @@
+/*
+ * The Mana World Server
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; 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 The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#include <map>
+
+#include "account-server/storage.hpp"
+#include "chat-server/chatchannelmanager.hpp"
+
+ChatChannelManager::ChatChannelManager()
+{
+ //Load stored public chat channels from db
+ Storage &store = Storage::instance("tmw");
+ mChatChannels = store.getChannelList();
+}
+
+
+ChatChannelManager::~ChatChannelManager()
+{
+ Storage &store = Storage::instance("tmw");
+ store.updateChannels(mChatChannels);
+ mChatChannels.clear();
+}
+
+short
+ChatChannelManager::registerPublicChannel(const std::string& channelName,
+ const std::string& channelAnnouncement, const std::string& channelPassword)
+{
+ short channelId = 1;
+ for (std::map<short, ChatChannel>::iterator i = mChatChannels.begin(),
+ end = mChatChannels.end(); i != end; ++i)
+ {
+ if ( i->second.getName() == channelName ) return 0;
+ // We seek the highest channelId in the public range
+ if (channelId <= i->first && i->first < (signed)MAX_PUBLIC_CHANNELS_RANGE)
+ channelId = i->first + 1;
+ }
+ // Too much channels registered
+ if (channelId >= (signed)MAX_PUBLIC_CHANNELS_RANGE) return 0;
+
+ // Register Channel
+ mChatChannels.insert(std::make_pair(channelId,ChatChannel(channelName,
+ channelAnnouncement, channelPassword)));
+ return channelId;
+}
+
+
+short
+ChatChannelManager::registerPrivateChannel(const std::string& channelName,
+ const std::string& channelAnnouncement, const std::string& channelPassword)
+{
+ short channelId = MAX_PUBLIC_CHANNELS_RANGE;
+ for (std::map<short, ChatChannel>::iterator i = mChatChannels.begin(),
+ end = mChatChannels.end(); i != end; ++i)
+ {
+ if ( i->second.getName() == channelName ) return 0;
+ // We seek the highest channelId in the private range
+ if (channelId <= i->first)
+ channelId = i->first + 1;
+ }
+ // Too much channels registered
+ if (channelId >= (signed)MAX_PRIVATE_CHANNELS_RANGE) return 0;
+
+ // Register Channel
+ mChatChannels.insert(std::make_pair(channelId,ChatChannel(channelName,
+ channelAnnouncement, channelPassword)));
+ return channelId;
+}
+
+bool ChatChannelManager::removeChannel(short channelId)
+{
+ std::map<short, ChatChannel>::iterator i = mChatChannels.find(channelId);
+ if (i == mChatChannels.end()) return false;
+ i->second.removeEveryUsersFromChannel();
+ mChatChannels.erase(i);
+ return true;
+}
+
+
+short ChatChannelManager::getChannelId(std::string const &channelName)
+{
+ for (std::map<short, ChatChannel>::const_iterator i = mChatChannels.begin(), i_end = mChatChannels.end();
+ i != i_end; ++i) {
+ if (i->second.getName() == channelName) return i->first;
+ }
+ return 0;
+}
+
+
+std::string ChatChannelManager::getChannelName(short channelId)
+{
+ std::map<short, ChatChannel>::iterator i = mChatChannels.find(channelId);
+ return (i != mChatChannels.end()) ? i->second.getName() : std::string();
+}
+
+std::string ChatChannelManager::getChannelAnnouncement(short channelId)
+{
+ std::map<short, ChatChannel>::iterator i = mChatChannels.find(channelId);
+ return (i != mChatChannels.end()) ? i->second.getAnnouncement() : std::string();
+}
+
+std::string ChatChannelManager::getChannelPassword(short channelId)
+{
+ std::map<short, ChatChannel>::iterator i = mChatChannels.find(channelId);
+ return (i != mChatChannels.end()) ? i->second.getPassword() : std::string();
+}
+
+bool ChatChannelManager::setChannelAnnouncement(short channelId, std::string const &channelAnnouncement)
+{
+ std::map<short, ChatChannel>::iterator i = mChatChannels.find(channelId);
+ if (i == mChatChannels.end()) return false;
+ i->second.setAnnouncement(channelAnnouncement);
+ return true;
+}
+
+bool ChatChannelManager::setChannelPassword(short channelId, std::string const &channelPassword)
+{
+ std::map<short, ChatChannel>::iterator i = mChatChannels.find(channelId);
+ if (i == mChatChannels.end()) return false;
+ i->second.setPassword(channelPassword);
+ return true;
+}
+
+ChatChannel ChatChannelManager::_getChannel(short channelId)
+{
+ std::map<short, ChatChannel>::iterator i = mChatChannels.find(channelId);
+ if (i != mChatChannels.end()) return i->second;
+ return ChatChannel("", "", "");
+}
+
+
+bool ChatChannelManager::addUserInChannel(std::string const &user, short channelId)
+{
+ std::map<short, ChatChannel>::iterator i = mChatChannels.find(channelId);
+ if (i == mChatChannels.end()) return false;
+ return i->second.addUserInChannel(user);
+}
+
+
+bool ChatChannelManager::removeUserFromChannel(std::string const &user, short channelId)
+{
+ std::map<short, ChatChannel>::iterator i = mChatChannels.find(channelId);
+ if (i == mChatChannels.end()) return false;
+ return i->second.removeUserFromChannel(user);
+}
+
+void ChatChannelManager::removeUserFromEveryChannels(std::string const &user)
+{
+ for (std::map<short, ChatChannel>::iterator i = mChatChannels.begin(), i_end = mChatChannels.end();
+ i != i_end; ++i) {
+ i->second.removeUserFromChannel(user);
+ }
+}
+
+std::vector< std::string > const &
+ChatChannelManager::getUserListInChannel(short channelId)
+{
+ std::map<short, ChatChannel>::iterator i = mChatChannels.find(channelId);
+ if (i != mChatChannels.end()) return i->second.getUserList();
+ static std::vector< std::string > emptyList;
+ return emptyList;
+}
+
+bool ChatChannelManager::isChannelRegistered(short channelId)
+{
+ std::map<short, ChatChannel>::iterator i = mChatChannels.find(channelId);
+ return i != mChatChannels.end();
+}
diff --git a/src/chat-server/chatchannelmanager.hpp b/src/chat-server/chatchannelmanager.hpp
new file mode 100644
index 00000000..fdb6d990
--- /dev/null
+++ b/src/chat-server/chatchannelmanager.hpp
@@ -0,0 +1,159 @@
+/*
+ * The Mana World Server
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; 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 The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#ifndef _TMWSERV_CHATCHANNELHANDLER_H_
+#define _TMWSERV_CHATCHANNELHANDLER_H_
+
+#include <map>
+
+#include "chat-server/chatchannel.hpp"
+
+class ChatChannelManager {
+
+public:
+
+ /**
+ * Constructor
+ */
+ ChatChannelManager();
+
+ /**
+ * Destructor
+ */
+ ~ChatChannelManager();
+
+ /**
+ * Add a public channel.
+ *
+ * @return the number of the channel registered.
+ * 0 if the registering was unsuccessful.
+ */
+ short registerPublicChannel(const std::string& channelName,
+ const std::string& channelAnnouncement,
+ const std::string& channelPassword);
+
+ /**
+ * Add a private channel.
+ *
+ * @return the number of the channel registered.
+ * 0 if the registering was unsuccessful.
+ */
+ short registerPrivateChannel(const std::string& channelName,
+ const std::string& channelAnnouncement,
+ const std::string& channelPassword);
+
+ /**
+ * Remove a channel.
+ */
+ bool removeChannel(short channelId);
+
+ /**
+ * Get the id of a channel from its name.
+ *
+ * @return the id of the channel
+ * 0 if it was unsuccessful.
+ */
+ short getChannelId(const std::string& channelName);
+
+ /**
+ * Get the name of a channel from its id.
+ *
+ * @return the name of the channel
+ */
+ std::string getChannelName(short channelId);
+
+ /**
+ * Get the announcement string of a channel from its id.
+ *
+ * @return the announcement string of the channel
+ */
+ std::string getChannelAnnouncement(short channelId);
+
+ /**
+ * Set the announcement string of a channel from its id.
+ *
+ * @return the announcement string of the channel
+ */
+ bool setChannelAnnouncement(short channelId, std::string const &channelAnnouncement);
+
+ /**
+ * Set the announcement string of a channel from its id.
+ *
+ * @return the announcement string of the channel
+ */
+ bool setChannelPassword(short channelId, const std::string& channelPassword);
+
+ /**
+ * Get the password of a channel from its id.
+ *
+ * @return the password of the channel
+ */
+ std::string getChannelPassword(short channelId);
+
+ /**
+ * get the ChatChannel object from its id.
+ *
+ * @return the ChatChannel object
+ */
+ ChatChannel _getChannel(short channelId);
+
+ /**
+ * Add a user in a channel
+ */
+ bool addUserInChannel(std::string const &, short channelId);
+
+ /**
+ * Remove a user from a channel.
+ */
+ bool removeUserFromChannel(std::string const &, short channelId);
+
+ /**
+ * Remove a user from every channels.
+ * Used at logout.
+ */
+ void removeUserFromEveryChannels(std::string const &);
+
+ /**
+ * Get the list of the users registered in a channel
+ */
+ std::vector< std::string > const &getUserListInChannel(short channelId);
+
+ /**
+ * tells if a channel exists
+ */
+ bool isChannelRegistered(short channelId);
+
+private:
+
+ /**
+ * The list keeping all the chat channels.
+ *
+ * The channel id must be unique.
+ */
+ std::map<short, ChatChannel> mChatChannels;
+
+};
+
+extern ChatChannelManager *chatChannelManager;
+
+#endif
diff --git a/src/chat-server/chathandler.cpp b/src/chat-server/chathandler.cpp
new file mode 100644
index 00000000..bb56c160
--- /dev/null
+++ b/src/chat-server/chathandler.cpp
@@ -0,0 +1,529 @@
+/*
+ * The Mana World Server
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; 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 The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#include "chat-server/chatchannelmanager.hpp"
+#include "chat-server/chathandler.hpp"
+#include "net/connectionhandler.hpp"
+#include "net/messagein.hpp"
+#include "net/messageout.hpp"
+#include "net/netcomputer.hpp"
+#include "utils/logger.h"
+#include "utils/stringfilter.h"
+
+
+class ChatClient: public NetComputer
+{
+ public:
+ /**
+ * Constructor.
+ */
+ ChatClient(ENetPeer *peer);
+
+ std::string characterName;
+ AccountLevel accountLevel;
+};
+
+ChatClient::ChatClient(ENetPeer *peer):
+ NetComputer(peer),
+ accountLevel(AL_NORMAL)
+{
+}
+
+struct ChatPendingLogin
+{
+ std::string character;
+ AccountLevel level;
+ int timeout;
+};
+
+typedef std::map< std::string, ChatPendingLogin > ChatPendingLogins;
+static ChatPendingLogins pendingLogins;
+
+typedef std::map< std::string, ChatClient * > ChatPendingClients;
+static ChatPendingClients pendingClients;
+
+void registerChatClient(std::string const &token, std::string const &name, int level)
+{
+ ChatPendingClients::iterator i = pendingClients.find(token);
+ if (i != pendingClients.end())
+ {
+ ChatClient *computer = i->second;
+ computer->characterName = name;
+ computer->accountLevel = (AccountLevel) level;
+ pendingClients.erase(i);
+ MessageOut result;
+ result.writeShort(CPMSG_CONNECT_RESPONSE);
+ result.writeByte(ERRMSG_OK);
+ computer->send(result);
+ }
+ else
+ {
+ ChatPendingLogin p;
+ p.character = name;
+ p.level = (AccountLevel) level;
+ p.timeout = 300; // world ticks
+ pendingLogins.insert(std::make_pair(token, p));
+ }
+}
+
+bool
+ChatHandler::startListen(enet_uint16 port)
+{
+ LOG_INFO("Chat handler started:", 0);
+ return ConnectionHandler::startListen(port);
+}
+
+void ChatHandler::removeOutdatedPending()
+{
+ ChatPendingLogins::iterator i = pendingLogins.begin(), next;
+ while (i != pendingLogins.end())
+ {
+ next = i; ++next;
+ if (--i->second.timeout <= 0) pendingLogins.erase(i);
+ i = next;
+ }
+}
+
+NetComputer *ChatHandler::computerConnected(ENetPeer *peer)
+{
+ return new ChatClient(peer);
+}
+
+void ChatHandler::computerDisconnected(NetComputer *computer)
+{
+ for (ChatPendingClients::iterator i = pendingClients.begin(), i_end = pendingClients.end();
+ i != i_end; ++i)
+ {
+ if (i->second == computer)
+ {
+ pendingClients.erase(i);
+ break;
+ }
+ }
+ delete computer;
+}
+
+void ChatHandler::process()
+{
+ ConnectionHandler::process();
+ removeOutdatedPending();
+}
+
+void ChatHandler::processMessage(NetComputer *comp, MessageIn &message)
+{
+ ChatClient &computer = *static_cast< ChatClient * >(comp);
+ MessageOut result;
+
+ if (computer.characterName.empty()) {
+ if (message.getId() != PCMSG_CONNECT) return;
+ std::string magic_token = message.readString(32);
+ ChatPendingLogins::iterator i = pendingLogins.find(magic_token);
+ if (i == pendingLogins.end())
+ {
+ for (ChatPendingClients::iterator i = pendingClients.begin(), i_end = pendingClients.end();
+ i != i_end; ++i) {
+ if (i->second == &computer) return;
+ }
+ pendingClients.insert(std::make_pair(magic_token, &computer));
+ return;
+ }
+ computer.characterName = i->second.character;
+ computer.accountLevel = i->second.level;
+ pendingLogins.erase(i);
+ result.writeShort(CPMSG_CONNECT_RESPONSE);
+ result.writeByte(ERRMSG_OK);
+ computer.send(result);
+ return;
+ }
+
+ switch (message.getId())
+ {
+ case PCMSG_CHAT:
+ {
+ // chat to people around area
+ std::string text = message.readString();
+ // If it's slang clean,
+ if (stringFilter->filterContent(text))
+ {
+ short channel = message.readShort();
+ LOG_INFO("Say: (Channel " << channel << "): " << text, 2);
+ if ( channel == 0 ) // Let's say that is the default channel for now.
+ {
+ if ( text.substr(0, 1) == "@" || text.substr(0, 1) == "#" || text.substr(0, 1) == "/" )
+ {
+ // The message is a command. Deal with it.
+ handleCommand(computer, text);
+ }
+ }
+ else
+ {
+ // We send the message to the players registered in the channel.
+ sayInChannel(computer, channel, text);
+ }
+ }
+ else
+ {
+ warnPlayerAboutBadWords(computer);
+ }
+ }
+ break;
+
+ case PCMSG_ANNOUNCE:
+ {
+ std::string text = message.readString();
+ // If it's slang's free.
+ if (stringFilter->filterContent(text))
+ {
+ // We send the message to every players in the default channel
+ // as it is an annouce.
+ announce(computer, text);
+ }
+ else
+ {
+ warnPlayerAboutBadWords(computer);
+ }
+ }
+ break;
+
+ case PCMSG_PRIVMSG:
+ {
+ std::string user = message.readString();
+ std::string text = message.readString();
+ if (stringFilter->filterContent(text))
+ {
+ // We seek the player to whom the message is told
+ // and send it to her/him.
+ sayToPlayer(computer, user, text);
+ }
+ else
+ {
+ warnPlayerAboutBadWords(computer);
+ }
+ } break;
+
+ // Channels handling
+ // =================
+ case PCMSG_REGISTER_CHANNEL:
+ {
+ result.writeShort(CPMSG_REGISTER_CHANNEL_RESPONSE);
+ // 0 public, 1 private
+ char channelType = message.readByte();
+ if (!channelType)
+ {
+ if (computer.accountLevel != AL_ADMIN &&
+ computer.accountLevel != AL_GM)
+ {
+ result.writeByte(ERRMSG_INSUFFICIENT_RIGHTS);
+ break;
+ }
+ }
+ std::string channelName = message.readString();
+ std::string channelAnnouncement = message.readString();
+ std::string channelPassword = message.readString();
+ // Checking datas
+ // Seeking double-quotes in strings
+ if (channelName.empty() || channelName.length() > MAX_CHANNEL_NAME ||
+ stringFilter->findDoubleQuotes(channelName))
+ {
+ result.writeByte(ERRMSG_INVALID_ARGUMENT);
+ break;
+ }
+ if (channelAnnouncement.length() > MAX_CHANNEL_ANNOUNCEMENT ||
+ stringFilter->findDoubleQuotes(channelAnnouncement))
+ {
+ result.writeByte(ERRMSG_INVALID_ARGUMENT);
+ break;
+ }
+ if (channelPassword.length() > MAX_CHANNEL_PASSWORD ||
+ stringFilter->findDoubleQuotes(channelPassword))
+ {
+ result.writeByte(ERRMSG_INVALID_ARGUMENT);
+ break;
+ }
+
+ // If it's slang's free.
+ if (stringFilter->filterContent(channelName) &&
+ stringFilter->filterContent(channelAnnouncement))
+ {
+ // We attempt to create a new channel
+ short channelId;
+ if (channelType)
+ channelId = chatChannelManager->registerPrivateChannel(channelName,
+ channelAnnouncement,
+ channelPassword);
+ else
+ channelId = chatChannelManager->registerPublicChannel(channelName,
+ channelAnnouncement,
+ channelPassword);
+ if (channelId != 0)
+ {
+ // We add the player as admin of this channel as he created it.
+ // The user registering a private channel is the only one to be able
+ // to update the password and the announcement in it and also to remove it.
+ chatChannelManager->addUserInChannel(computer.characterName, channelId);
+
+ result.writeByte(ERRMSG_OK);
+ result.writeShort(channelId);
+ break;
+ }
+ else
+ {
+ result.writeByte(ERRMSG_FAILURE);
+ break;
+ }
+ }
+ else
+ {
+ warnPlayerAboutBadWords(computer);
+ }
+ }
+ break;
+
+ case PCMSG_UNREGISTER_CHANNEL:
+ {
+ result.writeShort(CPMSG_UNREGISTER_CHANNEL_RESPONSE);
+
+ short channelId = message.readShort();
+ if (!chatChannelManager->isChannelRegistered(channelId))
+ {
+ result.writeByte(ERRMSG_INVALID_ARGUMENT);
+ }
+ else if (channelId < (signed)MAX_PUBLIC_CHANNELS_RANGE)
+ { // Public channel
+ if (computer.accountLevel == AL_ADMIN || computer.accountLevel == AL_GM)
+ {
+ warnUsersAboutPlayerEventInChat(channelId, "", CHAT_EVENT_LEAVING_PLAYER);
+ if (chatChannelManager->removeChannel(channelId))
+ result.writeByte(ERRMSG_OK);
+ else
+ result.writeByte(ERRMSG_FAILURE);
+ }
+ else
+ {
+ result.writeByte(ERRMSG_INSUFFICIENT_RIGHTS);
+ }
+ }
+ else
+ { // Private channel
+ // We first see if the user is the admin (first user) of the channel
+ std::vector< std::string > const &userList =
+ chatChannelManager->getUserListInChannel(channelId);
+ std::vector< std::string >::const_iterator i = userList.begin();
+ // if it's actually the private channel's admin
+ if (*i == computer.characterName)
+ {
+ // Make every user quit the channel
+ warnUsersAboutPlayerEventInChat(channelId, "", CHAT_EVENT_LEAVING_PLAYER);
+ if (chatChannelManager->removeChannel(channelId))
+ result.writeByte(ERRMSG_OK);
+ else
+ result.writeByte(ERRMSG_FAILURE);
+ }
+ else
+ {
+ result.writeByte(ERRMSG_INSUFFICIENT_RIGHTS);
+ }
+ }
+ } break;
+
+ case PCMSG_ENTER_CHANNEL:
+ {
+ result.writeShort(CPMSG_ENTER_CHANNEL_RESPONSE);
+ short channelId = message.readShort();
+ std::string givenPassword = message.readString();
+ if (channelId != 0 && chatChannelManager->isChannelRegistered(channelId))
+ {
+ std::string channelPassword = chatChannelManager->getChannelPassword(channelId);
+ if (!channelPassword.empty())
+ {
+ if (channelPassword != givenPassword)
+ {
+ result.writeByte(ERRMSG_INVALID_ARGUMENT);
+ break;
+ }
+ }
+ if (chatChannelManager->addUserInChannel(computer.characterName, channelId))
+ {
+ result.writeByte(ERRMSG_OK);
+ // The user entered the channel, now give him the announcement string
+ // and the user list.
+ result.writeString(chatChannelManager->getChannelAnnouncement(channelId));
+ std::vector< std::string > const &userList =
+ chatChannelManager->getUserListInChannel(channelId);
+ result.writeShort(userList.size());
+ for (std::vector< std::string >::const_iterator i = userList.begin(), i_end = userList.end();
+ i != i_end; ++i) {
+ result.writeString(*i);
+ }
+ // Send an CPMSG_UPDATE_CHANNEL to warn other clients a user went
+ // in the channel.
+ warnUsersAboutPlayerEventInChat(channelId, computer.characterName,
+ CHAT_EVENT_NEW_PLAYER);
+ }
+ else
+ {
+ result.writeByte(ERRMSG_FAILURE);
+ }
+ }
+ else
+ {
+ result.writeByte(ERRMSG_INVALID_ARGUMENT);
+ }
+ }
+ break;
+
+ case PCMSG_QUIT_CHANNEL:
+ {
+ result.writeShort(CPMSG_QUIT_CHANNEL_RESPONSE);
+ short channelId = message.readShort();
+ if (channelId != 0 && chatChannelManager->isChannelRegistered(channelId))
+ {
+ if (chatChannelManager->removeUserFromChannel(computer.characterName, channelId))
+ {
+ result.writeByte(ERRMSG_OK);
+ // Send an CPMSG_UPDATE_CHANNEL to warn other clients a user left
+ // the channel.
+ warnUsersAboutPlayerEventInChat(channelId, computer.characterName,
+ CHAT_EVENT_LEAVING_PLAYER);
+ }
+ else
+ {
+ result.writeByte(ERRMSG_FAILURE);
+ }
+ }
+ else
+ {
+ result.writeByte(ERRMSG_INVALID_ARGUMENT);
+ }
+ }
+ break;
+
+ default:
+ LOG_WARN("Invalid message type", 0);
+ result.writeShort(XXMSG_INVALID);
+ break;
+ }
+
+ if (result.getLength() > 0)
+ computer.send(result);
+}
+
+void ChatHandler::handleCommand(ChatClient &computer, std::string const &command)
+{
+ LOG_INFO("Chat: Received unhandled command: " << command, 2);
+ MessageOut result;
+ result.writeShort(CPMSG_ERROR);
+ result.writeByte(CHAT_UNHANDLED_COMMAND);
+ computer.send(result);
+}
+
+void ChatHandler::warnPlayerAboutBadWords(ChatClient &computer)
+{
+ // We could later count if the player is really often unpolite.
+ MessageOut result;
+ result.writeShort(CPMSG_ERROR);
+ result.writeByte(CHAT_USING_BAD_WORDS); // The Channel
+ computer.send(result);
+
+ LOG_INFO(computer.characterName << " says bad words.", 2);
+}
+
+void ChatHandler::announce(ChatClient &computer, std::string const &text)
+{
+ MessageOut result;
+ if (computer.accountLevel == AL_ADMIN ||
+ computer.accountLevel == AL_GM )
+ {
+ LOG_INFO("ANNOUNCE: " << text, 0);
+ // Send it to every beings.
+ result.writeShort(CPMSG_ANNOUNCEMENT);
+ result.writeString(text);
+ sendToEveryone(result);
+ }
+ else
+ {
+ result.writeShort(CPMSG_ERROR);
+ result.writeByte(ERRMSG_INSUFFICIENT_RIGHTS);
+ computer.send(result);
+ LOG_INFO(computer.characterName <<
+ " couldn't make an announcement due to insufficient rights.", 2);
+ }
+}
+
+void ChatHandler::sayToPlayer(ChatClient &computer, std::string const &playerName, std::string const &text)
+{
+ MessageOut result;
+ LOG_INFO(computer.characterName << " says to " << playerName << ": " << text, 2);
+ // Send it to the being if the being exists
+ result.writeShort(CPMSG_PRIVMSG);
+ result.writeString(computer.characterName);
+ result.writeString(text);
+ for (NetComputers::iterator i = clients.begin(), i_end = clients.end();
+ i != i_end; ++i) {
+ if (static_cast< ChatClient * >(*i)->characterName == playerName)
+ {
+ (*i)->send(result);
+ break;
+ }
+ }
+}
+
+void ChatHandler::sayInChannel(ChatClient &computer, short channel, std::string const &text)
+{
+ MessageOut result;
+ LOG_INFO(computer.characterName << " says in channel " << channel << ": " << text, 2);
+ // Send it to every beings in channel
+ result.writeShort(CPMSG_PUBMSG);
+ result.writeShort(channel);
+ result.writeString(computer.characterName);
+ result.writeString(text);
+ sendInChannel(channel, result);
+}
+
+void ChatHandler::warnUsersAboutPlayerEventInChat(short channelId,
+ std::string const &userName,
+ char eventId)
+{
+ MessageOut result;
+ result.writeShort(CPMSG_CHANNEL_EVENT);
+ result.writeShort(channelId);
+ result.writeByte(eventId);
+ result.writeString(userName);
+ sendInChannel(channelId, result);
+}
+
+void ChatHandler::sendInChannel(short channelId, MessageOut &msg)
+{
+ std::vector< std::string > const &users =
+ chatChannelManager->getUserListInChannel(channelId);
+ for (NetComputers::iterator i = clients.begin(), i_end = clients.end();
+ i != i_end; ++i) {
+ // If the being is in the channel, send it
+ std::vector< std::string >::const_iterator j_end = users.end(),
+ j = std::find(users.begin(), j_end, static_cast< ChatClient * >(*i)->characterName);
+ if (j != j_end)
+ {
+ (*i)->send(msg);
+ }
+ }
+}
diff --git a/src/chat-server/chathandler.hpp b/src/chat-server/chathandler.hpp
new file mode 100644
index 00000000..530a8115
--- /dev/null
+++ b/src/chat-server/chathandler.hpp
@@ -0,0 +1,99 @@
+/*
+ * The Mana World Server
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; 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 The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#ifndef _TMWSERV_CHATHANDLER_H_
+#define _TMWSERV_CHATHANDLER_H_
+
+#include <iosfwd>
+
+#include "net/connectionhandler.hpp"
+
+class ChatClient;
+
+/**
+ * Manages all chat related
+ */
+class ChatHandler : public ConnectionHandler
+{
+ public:
+ void process();
+
+ /**
+ * Start the handler
+ */
+ bool
+ startListen(enet_uint16 port);
+
+ protected:
+ /**
+ * Process chat related messages.
+ */
+ void processMessage(NetComputer *computer, MessageIn &message);
+ NetComputer *computerConnected(ENetPeer *);
+ void computerDisconnected(NetComputer *);
+
+ private:
+ /**
+ * Deal with command messages.
+ */
+ void handleCommand(ChatClient &computer, std::string const &command);
+
+ /**
+ * Tell the player to be more polite.
+ */
+ void warnPlayerAboutBadWords(ChatClient &computer);
+
+ /**
+ * Announce a message to every being in the default channel.
+ */
+ void announce(ChatClient &computer, std::string const &text);
+
+ /**
+ * Say something private to a player.
+ */
+ void sayToPlayer(ChatClient &computer, std::string const &playerName, std::string const &text);
+
+ /**
+ * Say something in a specific channel.
+ */
+ void sayInChannel(ChatClient &computer, short channel, std::string const &);
+
+ /**
+ * Send packet to every client in a registered channel.
+ */
+ void sendInChannel(short channelId, MessageOut &);
+
+ /**
+ * Tell a list of user about an event in a chatchannel about a player.
+ */
+ void warnUsersAboutPlayerEventInChat(short channelId, std::string const &userName, char eventId);
+
+ void removeOutdatedPending();
+};
+
+/**
+ * Register future client attempt. Temporary until physical server split.
+ */
+void registerChatClient(std::string const &, std::string const &, int);
+
+#endif