diff options
Diffstat (limited to 'src/chat-server')
-rw-r--r-- | src/chat-server/chatchannel.cpp | 117 | ||||
-rw-r--r-- | src/chat-server/chatchannel.hpp | 121 | ||||
-rw-r--r-- | src/chat-server/chatchannelmanager.cpp | 187 | ||||
-rw-r--r-- | src/chat-server/chatchannelmanager.hpp | 159 | ||||
-rw-r--r-- | src/chat-server/chathandler.cpp | 529 | ||||
-rw-r--r-- | src/chat-server/chathandler.hpp | 99 |
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 |