diff options
author | Bjørn Lindeijer <bjorn@lindeijer.nl> | 2007-07-20 20:33:34 +0000 |
---|---|---|
committer | Bjørn Lindeijer <bjorn@lindeijer.nl> | 2007-07-20 20:33:34 +0000 |
commit | 2c0a5ba8f1334b9ea3c0935ed16c7c580bb33243 (patch) | |
tree | b86acd9244ae604f8c21c34ace2ef8d1ce55ce67 /src/chat-server | |
parent | b41074c5c51ed9574bceddf94a727bbcd0513bd9 (diff) | |
download | manaserv-2c0a5ba8f1334b9ea3c0935ed16c7c580bb33243.tar.gz manaserv-2c0a5ba8f1334b9ea3c0935ed16c7c580bb33243.tar.bz2 manaserv-2c0a5ba8f1334b9ea3c0935ed16c7c580bb33243.tar.xz manaserv-2c0a5ba8f1334b9ea3c0935ed16c7c580bb33243.zip |
Separated ChatClient class from chathandler.cpp, cleaned up handling of
messages, defining a method for each handled message and some code formatting
cleanup and corrected headers.
Diffstat (limited to 'src/chat-server')
-rw-r--r-- | src/chat-server/chatclient.hpp | 49 | ||||
-rw-r--r-- | src/chat-server/chathandler.cpp | 884 | ||||
-rw-r--r-- | src/chat-server/chathandler.hpp | 66 |
3 files changed, 563 insertions, 436 deletions
diff --git a/src/chat-server/chatclient.hpp b/src/chat-server/chatclient.hpp new file mode 100644 index 00000000..c9578a50 --- /dev/null +++ b/src/chat-server/chatclient.hpp @@ -0,0 +1,49 @@ +/* + * 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_CHATCLIENT_H_ +#define _TMWSERV_CHATCLIENT_H_ + +#include "net/netcomputer.hpp" + +/** + * A client connected to the chat server. Via this class, the chat server + * keeps track of the character name and account level of a client. + */ +class ChatClient : public NetComputer +{ + public: + /** + * Constructor. + */ + ChatClient(ENetPeer *peer): + NetComputer(peer), + accountLevel(AL_NORMAL) + { + } + + std::string characterName; + AccountLevel accountLevel; +}; + +#endif diff --git a/src/chat-server/chathandler.cpp b/src/chat-server/chathandler.cpp index 64138816..21cebac0 100644 --- a/src/chat-server/chathandler.cpp +++ b/src/chat-server/chathandler.cpp @@ -29,6 +29,7 @@ #include "account-server/guildmanager.hpp" #include "account-server/serverhandler.hpp" #include "chat-server/chatchannelmanager.hpp" +#include "chat-server/chatclient.hpp" #include "chat-server/chathandler.hpp" #include "net/connectionhandler.hpp" #include "net/messagein.hpp" @@ -39,24 +40,6 @@ #include "utils/tokendispenser.hpp" -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; @@ -70,7 +53,9 @@ 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) +void registerChatClient(const std::string &token, + const std::string &name, + int level) { ChatPendingClients::iterator i = pendingClients.find(token); if (i != pendingClients.end()) @@ -94,8 +79,7 @@ void registerChatClient(std::string const &token, std::string const &name, int l } } -bool -ChatHandler::startListen(enet_uint16 port) +bool ChatHandler::startListen(enet_uint16 port) { LOG_INFO("Chat handler started:"); return ConnectionHandler::startListen(port); @@ -175,377 +159,44 @@ void ChatHandler::processMessage(NetComputer *comp, MessageIn &message) 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_DEBUG("Say: (Channel " << channel << "): " << text); - // Let's say that channel 0 is the default channel for now. - if (channel == 0) - { - // TODO: I think commands should be / only - BL - 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); - } - } + handleChatMessage(computer, message); break; case PCMSG_ANNOUNCE: - { - std::string text = message.readString(); - // If it's slang's free. - if (stringFilter->filterContent(text)) - { - // We send the message to all players in the default - // channel as it is an announce. - announce(computer, text); - } - else - { - warnPlayerAboutBadWords(computer); - } - } + handleAnnounceMessage(computer, message); 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 - // ================= + handlePrivMsgMessage(computer, message); + break; + 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) - { - // Removed the need for admin/gm rights to create public channels - // 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 (guildManager->doesExist(channelName)) - { - 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); - result.writeString(channelName); - break; - } - else - { - result.writeByte(ERRMSG_FAILURE); - break; - } - } - else - { - warnPlayerAboutBadWords(computer); - } - } + handleRegisterChannelMessage(computer, message); break; case PCMSG_UNREGISTER_CHANNEL: - { - result.writeShort(CPMSG_UNREGISTER_CHANNEL_RESPONSE); - - short channelId = message.readShort(); - std::string channelName = chatChannelManager->getChannelName(channelId); - - // Get character based on name. - CharacterPtr character = serverHandler->getCharacter(computer.characterName); - - if (!chatChannelManager->channelExists(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 if (guildManager->doesExist(channelName)) - { - Guild *guild = guildManager->findByName(channelName); - if (guild->checkLeader(character.get())) - { - chatChannelManager->removeChannel(channelId); - guildManager->removeGuild(guild->getId()); - result.writeByte(ERRMSG_OK); - } - } - 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; + handleUnregisterChannelMessage(computer, message); + break; case PCMSG_ENTER_CHANNEL: - { - result.writeShort(CPMSG_ENTER_CHANNEL_RESPONSE); - std::string channelName = message.readString(); - std::string givenPassword = message.readString(); - short channelId = chatChannelManager->getChannelId(channelName); - if (channelId != 0 && chatChannelManager->channelExists(channelId)) - { - std::string channelPassword = chatChannelManager->getChannelPassword(channelId); - if (!channelPassword.empty()) - { - if (channelPassword != givenPassword) - { - result.writeByte(ERRMSG_INVALID_ARGUMENT); - break; - } - } - - if (guildManager->doesExist(channelName)) - { - Guild *guild = guildManager->findByName(channelName); - if (!guild->checkInGuild(computer.characterName)) - { - result.writeByte(ERRMSG_INVALID_ARGUMENT); - break; - } - sendUserJoined(channelId, computer.characterName); - } - if (chatChannelManager->addUserInChannel(computer.characterName, channelId)) - { - result.writeByte(ERRMSG_OK); - // The user entered the channel, now give him the channel - // id, the announcement string and the user list. - result.writeShort(channelId); - result.writeString(channelName); - result.writeString(chatChannelManager->getChannelAnnouncement(channelId)); - std::vector< std::string > const &userList = - chatChannelManager->getUserListInChannel(channelId); - 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; + handleEnterChannelMessage(computer, message); + break; case PCMSG_QUIT_CHANNEL: - { - result.writeShort(CPMSG_QUIT_CHANNEL_RESPONSE); - short channelId = message.readShort(); - std::string channelName = chatChannelManager->getChannelName(channelId); - - if (channelId != 0 && chatChannelManager->channelExists(channelId)) - { - if (chatChannelManager->removeUserFromChannel(computer.characterName, channelId)) - { - result.writeByte(ERRMSG_OK); - result.writeShort(channelId); - // Send an CPMSG_UPDATE_CHANNEL to warn other clients a - // user left the channel. - warnUsersAboutPlayerEventInChat(channelId, - computer.characterName, - CHAT_EVENT_LEAVING_PLAYER); - if (guildManager->doesExist(channelName)) - { - // Send a user left message - sendUserLeft(channelId, computer.characterName); - } - } - else - { - result.writeByte(ERRMSG_FAILURE); - } - } - else - { - result.writeByte(ERRMSG_INVALID_ARGUMENT); - } - } - break; + handleQuitChannelMessage(computer, message); + break; case PCMSG_LIST_CHANNELS: - { - result.writeShort(CPMSG_LIST_CHANNELS_RESPONSE); - - std::list<std::string> publicChannels = - chatChannelManager->getPublicChannelNames(); - std::list<std::string>::iterator i, i_end; - - for (i = publicChannels.begin(), i_end = publicChannels.end(); - i != i_end; ++i) - { - short users = chatChannelManager->getNumberOfChannelUsers(*i); - result.writeString(*i); - result.writeShort(users); - } - } - break; + handleListChannelsMessage(computer, message); + break; case PCMSG_LIST_CHANNELUSERS: - { - result.writeShort(CPMSG_LIST_CHANNELUSERS_RESPONSE); - - std::string channelName = message.readString(); - - result.writeString(channelName); - - // Get user list - std::vector<std::string> channelList; - channelList = chatChannelManager->getUserListInChannel( - chatChannelManager->getChannelId(channelName)); - - // Add a user at a time - for (int i = 0; i < channelList.size(); ++i) - { - result.writeString(channelList[i]); - } - } break; + handleListChannelUsersMessage(computer, message); + break; case PCMSG_DISCONNECT: - { - result.writeShort(CPMSG_DISCONNECT_RESPONSE); - result.writeByte(ERRMSG_OK); - chatChannelManager->removeUserFromAllChannels( - computer.characterName); - } - break; + handleDisconnectMessage(computer, message); + break; default: LOG_WARN("ChatHandler::processMessage, Invalid message type" @@ -559,7 +210,7 @@ void ChatHandler::processMessage(NetComputer *comp, MessageIn &message) } void -ChatHandler::handleCommand(ChatClient &computer, std::string const &command) +ChatHandler::handleCommand(ChatClient &computer, const std::string &command) { LOG_INFO("Chat: Received unhandled command: " << command); MessageOut result; @@ -581,31 +232,432 @@ ChatHandler::warnPlayerAboutBadWords(ChatClient &computer) } void -ChatHandler::announce(ChatClient &computer, std::string const &text) +ChatHandler::handleChatMessage(ChatClient &client, MessageIn &msg) { - MessageOut result; - if (computer.accountLevel == AL_ADMIN || - computer.accountLevel == AL_GM ) + std::string text = msg.readString(); + + // Pass it through the slang filter (false when it contains bad words) + if (!stringFilter->filterContent(text)) + { + warnPlayerAboutBadWords(client); + return; + } + + short channel = msg.readShort(); + + LOG_DEBUG(client.characterName << " says in channel " << channel << ": " + << text); + + MessageOut result(CPMSG_PUBMSG); + result.writeShort(channel); + result.writeString(client.characterName); + result.writeString(text); + + // Send the message to the players registered in the channel. + sendInChannel(channel, result); +} + +void +ChatHandler::handleAnnounceMessage(ChatClient &client, MessageIn &msg) +{ + std::string text = msg.readString(); + + if (!stringFilter->filterContent(text)) { + warnPlayerAboutBadWords(client); + return; + } + + if (client.accountLevel == AL_ADMIN || client.accountLevel == AL_GM) + { + // TODO: b_lindeijer: Shouldn't announcements also have a sender? LOG_INFO("ANNOUNCE: " << text); - // Send it to all beings. - result.writeShort(CPMSG_ANNOUNCEMENT); + MessageOut result(CPMSG_ANNOUNCEMENT); result.writeString(text); + + // We send the message to all players in the default channel as it is + // an announcement. sendToEveryone(result); } else { - result.writeShort(CPMSG_ERROR); + MessageOut result(CPMSG_ERROR); result.writeByte(ERRMSG_INSUFFICIENT_RIGHTS); - computer.send(result); - LOG_INFO(computer.characterName << + client.send(result); + LOG_INFO(client.characterName << " couldn't make an announcement due to insufficient rights."); } } void -ChatHandler::sayToPlayer(ChatClient &computer, std::string const &playerName, - std::string const &text) +ChatHandler::handlePrivMsgMessage(ChatClient &client, MessageIn &msg) +{ + std::string user = msg.readString(); + std::string text = msg.readString(); + + if (!stringFilter->filterContent(text)) + { + warnPlayerAboutBadWords(client); + return; + } + + // We seek the player to whom the message is told and send it to her/him. + sayToPlayer(client, user, text); +} + +void +ChatHandler::handleRegisterChannelMessage(ChatClient &client, MessageIn &msg) +{ + MessageOut reply(CPMSG_REGISTER_CHANNEL_RESPONSE); + + char channelType = msg.readByte(); + if (!channelType) // 0 public, 1 private + { + if (client.accountLevel != AL_ADMIN && + client.accountLevel != AL_GM) + { + // Removed the need for admin/gm rights to create public channels + //reply.writeByte(ERRMSG_INSUFFICIENT_RIGHTS); + //send message + //return; + } + } + + std::string channelName = msg.readString(); + std::string channelAnnouncement = msg.readString(); + std::string channelPassword = msg.readString(); + + if (!stringFilter->filterContent(channelName) || + !stringFilter->filterContent(channelAnnouncement)) + { + warnPlayerAboutBadWords(client); + return; + } + + // Checking strings for length and double quotes + if (channelName.empty() || + channelName.length() > MAX_CHANNEL_NAME || + stringFilter->findDoubleQuotes(channelName) || + channelAnnouncement.length() > MAX_CHANNEL_ANNOUNCEMENT || + stringFilter->findDoubleQuotes(channelAnnouncement) || + channelPassword.length() > MAX_CHANNEL_PASSWORD || + stringFilter->findDoubleQuotes(channelPassword)) + { + reply.writeByte(ERRMSG_INVALID_ARGUMENT); + } + else if (guildManager->doesExist(channelName)) + { + // Channel already exists + reply.writeByte(ERRMSG_INVALID_ARGUMENT); + } + else + { + // We attempt to create a new channel + short channelId; + + // TODO: b_lindeijer: These methods should really be combined. + if (channelType) + { + channelId = chatChannelManager->registerPrivateChannel( + channelName, + channelAnnouncement, + channelPassword); + } + else + { + channelId = chatChannelManager->registerPublicChannel( + channelName, + channelAnnouncement, + channelPassword); + } + + if (channelId) + { + // 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(client.characterName, + channelId); + + reply.writeByte(ERRMSG_OK); + reply.writeShort(channelId); + reply.writeString(channelName); + } + else + { + reply.writeByte(ERRMSG_FAILURE); + } + } + + client.send(reply); +} + +void +ChatHandler::handleUnregisterChannelMessage(ChatClient &client, MessageIn &msg) +{ + MessageOut reply(CPMSG_UNREGISTER_CHANNEL_RESPONSE); + + short channelId = msg.readShort(); + + if (!chatChannelManager->channelExists(channelId)) + { + // Channel doesn't exist + reply.writeByte(ERRMSG_INVALID_ARGUMENT); + } + else if (channelId < (signed) MAX_PUBLIC_CHANNELS_RANGE) + { + // Public channel + + // Get character based on name + CharacterPtr character = + serverHandler->getCharacter(client.characterName); + std::string channelName = chatChannelManager->getChannelName(channelId); + + if (client.accountLevel == AL_ADMIN || client.accountLevel == AL_GM) + { + warnUsersAboutPlayerEventInChat( + channelId, "", CHAT_EVENT_LEAVING_PLAYER); + if (chatChannelManager->removeChannel(channelId)) + reply.writeByte(ERRMSG_OK); + else + reply.writeByte(ERRMSG_FAILURE); + } + else if (guildManager->doesExist(channelName)) + { + Guild *guild = guildManager->findByName(channelName); + if (guild->checkLeader(character.get())) + { + // TODO: b_lindeijer: I think it would be better if guild + // channels were removed in response to a guild being + // removed, as opposed to removing a guild because its + // channel disappears. + chatChannelManager->removeChannel(channelId); + guildManager->removeGuild(guild->getId()); + reply.writeByte(ERRMSG_OK); + } + else + { + reply.writeByte(ERRMSG_INSUFFICIENT_RIGHTS); + } + } + else + { + reply.writeByte(ERRMSG_INSUFFICIENT_RIGHTS); + } + } + else + { + // Private channel + + // We first see if the user is the admin (first user) of the channel + const std::vector<std::string> &userList = + chatChannelManager->getUserListInChannel(channelId); + std::vector<std::string>::const_iterator i = userList.begin(); + // If it's actually the private channel's admin + if (*i == client.characterName) + { + // Make every user quit the channel + warnUsersAboutPlayerEventInChat( + channelId, "", CHAT_EVENT_LEAVING_PLAYER); + if (chatChannelManager->removeChannel(channelId)) { + reply.writeByte(ERRMSG_OK); + } + else + { + reply.writeByte(ERRMSG_FAILURE); + } + } + else + { + reply.writeByte(ERRMSG_INSUFFICIENT_RIGHTS); + } + } + + client.send(reply); +} + +void +ChatHandler::handleEnterChannelMessage(ChatClient &client, MessageIn &msg) +{ + MessageOut reply(CPMSG_ENTER_CHANNEL_RESPONSE); + + std::string channelName = msg.readString(); + std::string givenPassword = msg.readString(); + + short channelId = chatChannelManager->getChannelId(channelName); + std::string channelPassword = + chatChannelManager->getChannelPassword(channelId); + + // TODO: b_lindeijer: Currently, the client has to join its guild channels + // explicitly by sending 'enter channel' messages. This should be + // changed to implicitly joining relevant guild channels right after + // login. + Guild *guild = guildManager->findByName(channelName); + + if (!channelId || !chatChannelManager->channelExists(channelId)) + { + reply.writeByte(ERRMSG_INVALID_ARGUMENT); + } + else if (!channelPassword.empty() && channelPassword != givenPassword) + { + // Incorrect password (should probably have its own return value) + reply.writeByte(ERRMSG_INVALID_ARGUMENT); + } + else if (guild && !guild->checkInGuild(client.characterName)) + { + // Player tried to join a guild channel of a guild he's not a member of + reply.writeByte(ERRMSG_INVALID_ARGUMENT); + } + else + { + // In the case of a guild, send user joined message. + if (guild) + { + sendUserJoined(channelId, client.characterName); + } + + if (chatChannelManager->addUserInChannel(client.characterName, + channelId)) + { + reply.writeByte(ERRMSG_OK); + // The user entered the channel, now give him the channel + // id, the announcement string and the user list. + reply.writeShort(channelId); + reply.writeString(channelName); + reply.writeString( + chatChannelManager->getChannelAnnouncement(channelId)); + const std::vector<std::string> &userList = + chatChannelManager->getUserListInChannel(channelId); + + for (std::vector<std::string>::const_iterator i = userList.begin(), + i_end = userList.end(); + i != i_end; ++i) + { + reply.writeString(*i); + } + // Send an CPMSG_UPDATE_CHANNEL to warn other clients a user went + // in the channel. + warnUsersAboutPlayerEventInChat(channelId, + client.characterName, + CHAT_EVENT_NEW_PLAYER); + } + else + { + reply.writeByte(ERRMSG_FAILURE); + } + } + + client.send(reply); +} + +void +ChatHandler::handleQuitChannelMessage(ChatClient &client, MessageIn &msg) +{ + MessageOut reply(CPMSG_QUIT_CHANNEL_RESPONSE); + + short channelId = msg.readShort(); + + if (channelId != 0 && chatChannelManager->channelExists(channelId)) + { + if (chatChannelManager->removeUserFromChannel(client.characterName, + channelId)) + { + reply.writeByte(ERRMSG_OK); + reply.writeShort(channelId); + + // Send an CPMSG_UPDATE_CHANNEL to warn other clients a user left + // the channel. + warnUsersAboutPlayerEventInChat(channelId, + client.characterName, + CHAT_EVENT_LEAVING_PLAYER); + + // TODO: b_lindeijer: Clients aren't supposed to quit guild + // channels explicitly, this should rather happen + // implicitly. See similar note at handling 'enter channel' + // messages. + std::string channelName = + chatChannelManager->getChannelName(channelId); + + if (guildManager->doesExist(channelName)) + { + // Send a user left message + sendUserLeft(channelId, client.characterName); + } + } + else + { + reply.writeByte(ERRMSG_FAILURE); + } + } + else + { + reply.writeByte(ERRMSG_INVALID_ARGUMENT); + } + + client.send(reply); +} + +void +ChatHandler::handleListChannelsMessage(ChatClient &client, MessageIn &msg) +{ + MessageOut reply(CPMSG_LIST_CHANNELS_RESPONSE); + + std::list<std::string> publicChannels = + chatChannelManager->getPublicChannelNames(); + + for (std::list<std::string>::iterator i = publicChannels.begin(), + i_end = publicChannels.end(); + i != i_end; ++i) + { + const std::string &name = *i; + short users = chatChannelManager->getNumberOfChannelUsers(name); + reply.writeString(name); + reply.writeShort(users); + } + + client.send(reply); +} + +void +ChatHandler::handleListChannelUsersMessage(ChatClient &client, MessageIn &msg) +{ + MessageOut reply(CPMSG_LIST_CHANNELUSERS_RESPONSE); + + // TODO: b_lindeijer: Since it only makes sense to ask for the list of + // users in a channel you're in, this message should really take + // a channel id instead. + std::string channelName = msg.readString(); + + reply.writeString(channelName); + + std::vector<std::string> channelUsers = + chatChannelManager->getUserListInChannel( + chatChannelManager->getChannelId(channelName)); + + // TODO: b_lindeijer: This method should check whether the channel exists. + + // Add a user at a time + for (unsigned int i = 0; i < channelUsers.size(); ++i) + { + reply.writeString(channelUsers[i]); + } + + client.send(reply); +} + +void +ChatHandler::handleDisconnectMessage(ChatClient &client, MessageIn &msg) +{ + MessageOut reply(CPMSG_DISCONNECT_RESPONSE); + reply.writeByte(ERRMSG_OK); + chatChannelManager->removeUserFromAllChannels(client.characterName); + client.send(reply); +} + +void +ChatHandler::sayToPlayer(ChatClient &computer, const std::string &playerName, + const std::string &text) { MessageOut result; LOG_DEBUG(computer.characterName << " says to " << playerName << ": " @@ -624,23 +676,8 @@ ChatHandler::sayToPlayer(ChatClient &computer, std::string const &playerName, } } -void -ChatHandler::sayInChannel(ChatClient &computer, short channel, - std::string const &text) -{ - MessageOut result; - LOG_DEBUG(computer.characterName << " says in channel " << channel << ": " - << text); - // Send it to all 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, + const std::string &userName, char eventId) { MessageOut result; @@ -653,25 +690,34 @@ void ChatHandler::warnUsersAboutPlayerEventInChat(short channelId, void ChatHandler::sendInChannel(short channelId, MessageOut &msg) { - std::vector< std::string > const &users = + // TODO: b_lindeijer: Instead of looping through the channel users for each + // connected client, it would be much better to directly associate + // the connected clients with the channel. + + const std::vector<std::string> &users = chatChannelManager->getUserListInChannel(channelId); + for (NetComputers::iterator i = clients.begin(), i_end = clients.end(); i != i_end; ++i) { + const std::string &name = static_cast<ChatClient*>(*i)->characterName; + std::vector<std::string>::const_iterator j_end = users.end(); + // 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) - { + if (std::find(users.begin(), j_end, name) != j_end) (*i)->send(msg); - } } } -void ChatHandler::sendGuildEnterChannel(const MessageOut &msg, const std::string &name) +void ChatHandler::sendGuildEnterChannel(const MessageOut &msg, + const std::string &name) { + // TODO: b_lindeijer: This method is just an inefficient way to send a + // message to a player with a certain name. Would be good to get + // rid of it. for (NetComputers::iterator i = clients.begin(), i_end = clients.end(); - i != i_end; ++i) { + i != i_end; ++i) + { if (static_cast< ChatClient * >(*i)->characterName == name) { (*i)->send(msg); @@ -680,14 +726,20 @@ void ChatHandler::sendGuildEnterChannel(const MessageOut &msg, const std::string } } -void ChatHandler::sendGuildInvite(const std::string &invitedName, const std::string &inviterName, +void ChatHandler::sendGuildInvite(const std::string &invitedName, + const std::string &inviterName, const std::string &guildName) { MessageOut msg(CPMSG_GUILD_INVITED); msg.writeString(inviterName); msg.writeString(guildName); + + // TODO: b_lindeijer: This is just an inefficient way to send a message to + // a player with a certain name. Would be good if the invitedName + // could be replaced with a ChatClient. for (NetComputers::iterator i = clients.begin(), i_end = clients.end(); - i != i_end; ++i) { + i != i_end; ++i) + { if (static_cast< ChatClient * >(*i)->characterName == invitedName) { (*i)->send(msg); @@ -696,22 +748,22 @@ void ChatHandler::sendGuildInvite(const std::string &invitedName, const std::str } } -void ChatHandler::sendGuildRejoin(ChatClient &computer) +void ChatHandler::sendGuildRejoin(ChatClient &client) { // Get character based on name. - CharacterPtr character = serverHandler->getCharacter(computer.characterName); + CharacterPtr character = serverHandler->getCharacter(client.characterName); // Get list of guilds and check what rights they have. std::vector<std::string> guilds = character->getGuilds(); - for(unsigned int i = 0; i != guilds.size(); ++i) + for (unsigned int i = 0; i != guilds.size(); ++i) { Guild *guild = guildManager->findByName(guilds[i]); short leader = 0; - if(!guild) + if (!guild) { return; } - if(guild->checkLeader(character.get())) + if (guild->checkLeader(character.get())) { leader = 1; } @@ -719,7 +771,7 @@ void ChatHandler::sendGuildRejoin(ChatClient &computer) msg.writeString(guild->getName()); msg.writeShort(guild->getId()); msg.writeShort(leader); - computer.send(msg); + client.send(msg); serverHandler->enterChannel(guild->getName(), character.get()); } } diff --git a/src/chat-server/chathandler.hpp b/src/chat-server/chathandler.hpp index 19d2fc31..6e8bf29a 100644 --- a/src/chat-server/chathandler.hpp +++ b/src/chat-server/chathandler.hpp @@ -51,19 +51,18 @@ class ChatHandler : public ConnectionHandler /** * Start the handler. */ - bool - startListen(enet_uint16 port); + bool startListen(enet_uint16 port); /** * Tell a list of users about an event in a chatchannel about a player. */ void warnUsersAboutPlayerEventInChat(short channelId, - std::string const &userName, + const std::string &userName, char eventId); /** - * Send Chat and Guild Info to chat client, so that they can - * join the correct channels. + * Send chat and guild info to chat client, so that they can join the + * correct channels. */ void sendGuildEnterChannel(const MessageOut &msg, const std::string &name); @@ -80,7 +79,15 @@ class ChatHandler : public ConnectionHandler * Process chat related messages. */ void processMessage(NetComputer *computer, MessageIn &message); + + /** + * Returns a ChatClient instance. + */ NetComputer *computerConnected(ENetPeer *); + + /** + * Cleans up after the disconnected client. + */ void computerDisconnected(NetComputer *); /** @@ -92,7 +99,37 @@ class ChatHandler : public ConnectionHandler /** * Deal with command messages. */ - void handleCommand(ChatClient &computer, std::string const &command); + void handleCommand(ChatClient &client, const std::string &command); + + void + handleChatMessage(ChatClient &client, MessageIn &msg); + + void + handleAnnounceMessage(ChatClient &client, MessageIn &msg); + + void + handlePrivMsgMessage(ChatClient &client, MessageIn &msg); + + void + handleRegisterChannelMessage(ChatClient &client, MessageIn &msg); + + void + handleUnregisterChannelMessage(ChatClient &client, MessageIn &msg); + + void + handleEnterChannelMessage(ChatClient &client, MessageIn &msg); + + void + handleQuitChannelMessage(ChatClient &client, MessageIn &msg); + + void + handleListChannelsMessage(ChatClient &client, MessageIn &msg); + + void + handleListChannelUsersMessage(ChatClient &client, MessageIn &msg); + + void + handleDisconnectMessage(ChatClient &client, MessageIn &msg); /** * Tell the player to be more polite. @@ -100,21 +137,10 @@ class ChatHandler : public ConnectionHandler 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 &); + void sayToPlayer(ChatClient &computer, const std::string &playerName, + const std::string &text); /** * Send packet to every client in a registered channel. @@ -141,7 +167,7 @@ class ChatHandler : public ConnectionHandler /** * Register future client attempt. Temporary until physical server split. */ -void registerChatClient(std::string const &, std::string const &, int); +void registerChatClient(const std::string &, const std::string &, int); extern ChatHandler *chatHandler; |