00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <list>
00023 #include <algorithm>
00024 #include <string>
00025 #include <sstream>
00026
00027 #include "defines.h"
00028 #include "account-server/character.hpp"
00029 #include "account-server/dalstorage.hpp"
00030 #include "chat-server/guildmanager.hpp"
00031 #include "chat-server/chatchannelmanager.hpp"
00032 #include "chat-server/chatclient.hpp"
00033 #include "chat-server/chathandler.hpp"
00034 #include "common/transaction.hpp"
00035 #include "net/connectionhandler.hpp"
00036 #include "net/messagein.hpp"
00037 #include "net/messageout.hpp"
00038 #include "net/netcomputer.hpp"
00039 #include "utils/logger.h"
00040 #include "utils/stringfilter.h"
00041 #include "utils/tokendispenser.hpp"
00042
00043 void registerChatClient(const std::string &token,
00044 const std::string &name,
00045 int level)
00046 {
00047 ChatHandler::Pending *p = new ChatHandler::Pending;
00048 p->character = name;
00049 p->level = level;
00050 chatHandler->mTokenCollector.addPendingConnect(token, p);
00051 }
00052
00053 ChatHandler::ChatHandler():
00054 mTokenCollector(this)
00055 {
00056 }
00057
00058 bool ChatHandler::startListen(enet_uint16 port)
00059 {
00060 LOG_INFO("Chat handler started:");
00061 return ConnectionHandler::startListen(port);
00062 }
00063
00064 void ChatHandler::deletePendingClient(ChatClient *c)
00065 {
00066 MessageOut msg(CPMSG_CONNECT_RESPONSE);
00067 msg.writeByte(ERRMSG_TIME_OUT);
00068
00069
00070 c->disconnect(msg);
00071 }
00072
00073 void ChatHandler::deletePendingConnect(Pending *p)
00074 {
00075 delete p;
00076 }
00077
00078 void ChatHandler::tokenMatched(ChatClient *client, Pending *p)
00079 {
00080 MessageOut msg(CPMSG_CONNECT_RESPONSE);
00081
00082 client->characterName = p->character;
00083 client->accountLevel = p->level;
00084
00085 Character *c = storage->getCharacter(p->character);
00086
00087 if (!c)
00088 {
00089
00090 msg.writeByte(ERRMSG_FAILURE);
00091 }
00092 else
00093 {
00094 client->characterId = c->getDatabaseID();
00095 delete p;
00096
00097 msg.writeByte(ERRMSG_OK);
00098
00099
00100 mPlayerMap.insert(std::pair<std::string, ChatClient*>(client->characterName, client));
00101 }
00102
00103 client->send(msg);
00104
00105 }
00106
00107 NetComputer *ChatHandler::computerConnected(ENetPeer *peer)
00108 {
00109 return new ChatClient(peer);
00110 }
00111
00112 void ChatHandler::computerDisconnected(NetComputer *comp)
00113 {
00114 ChatClient *computer = static_cast< ChatClient * >(comp);
00115
00116 if (computer->characterName.empty())
00117 {
00118
00119 mTokenCollector.deletePendingClient(computer);
00120 }
00121 else
00122 {
00123
00124 chatChannelManager->removeUserFromAllChannels(computer);
00125
00126
00127 removeUserFromParty(*computer);
00128
00129
00130
00131
00132 mPlayerMap.erase(computer->characterName);
00133 }
00134
00135 delete computer;
00136 }
00137
00138 void ChatHandler::processMessage(NetComputer *comp, MessageIn &message)
00139 {
00140 ChatClient &computer = *static_cast< ChatClient * >(comp);
00141 MessageOut result;
00142
00143 if (computer.characterName.empty())
00144 {
00145 if (message.getId() != PCMSG_CONNECT) return;
00146
00147 std::string magic_token = message.readString(MAGIC_TOKEN_LENGTH);
00148 mTokenCollector.addPendingClient(magic_token, &computer);
00149 sendGuildRejoin(computer);
00150 return;
00151 }
00152
00153 switch (message.getId())
00154 {
00155 case PCMSG_CHAT:
00156 handleChatMessage(computer, message);
00157 break;
00158
00159 case PCMSG_ANNOUNCE:
00160 handleAnnounceMessage(computer, message);
00161 break;
00162
00163 case PCMSG_PRIVMSG:
00164 handlePrivMsgMessage(computer, message);
00165 break;
00166
00167 case PCMSG_WHO:
00168 handleWhoMessage(computer);
00169 break;
00170
00171 case PCMSG_ENTER_CHANNEL:
00172 handleEnterChannelMessage(computer, message);
00173 break;
00174
00175 case PCMSG_USER_MODE:
00176 handleModeChangeMessage(computer, message);
00177 break;
00178
00179 case PCMSG_KICK_USER:
00180 handleKickUserMessage(computer, message);
00181
00182 case PCMSG_QUIT_CHANNEL:
00183 handleQuitChannelMessage(computer, message);
00184 break;
00185
00186 case PCMSG_LIST_CHANNELS:
00187 handleListChannelsMessage(computer, message);
00188 break;
00189
00190 case PCMSG_LIST_CHANNELUSERS:
00191 handleListChannelUsersMessage(computer, message);
00192 break;
00193
00194 case PCMSG_TOPIC_CHANGE:
00195 handleTopicChange(computer, message);
00196 break;
00197
00198 case PCMSG_DISCONNECT:
00199 handleDisconnectMessage(computer, message);
00200 break;
00201
00202 case PCMSG_GUILD_CREATE:
00203 handleGuildCreation(computer, message);
00204 break;
00205
00206 case PCMSG_GUILD_INVITE:
00207 handleGuildInvitation(computer, message);
00208 break;
00209
00210 case PCMSG_GUILD_ACCEPT:
00211 handleGuildAcceptInvite(computer, message);
00212 break;
00213
00214 case PCMSG_GUILD_GET_MEMBERS:
00215 handleGuildRetrieveMembers(computer, message);
00216 break;
00217
00218 case PCMSG_GUILD_PROMOTE_MEMBER:
00219 handleGuildMemberLevelChange(computer, message);
00220 break;
00221
00222 case PCMSG_GUILD_KICK_MEMBER:
00223 handleGuildMemberKick(computer, message);
00224
00225 case PCMSG_GUILD_QUIT:
00226 handleGuildQuit(computer, message);
00227 break;
00228
00229 case PCMSG_PARTY_INVITE:
00230 handlePartyInvite(computer, message);
00231 break;
00232
00233 case PCMSG_PARTY_ACCEPT_INVITE:
00234 handlePartyAcceptInvite(computer, message);
00235 break;
00236
00237 case PCMSG_PARTY_QUIT:
00238 handlePartyQuit(computer);
00239 break;
00240
00241 case PCMSG_PARTY_REJECT_INVITE:
00242 handlePartyRejection(computer, message);
00243 break;
00244
00245 default:
00246 LOG_WARN("ChatHandler::processMessage, Invalid message type"
00247 << message.getId());
00248 result.writeShort(XXMSG_INVALID);
00249 break;
00250 }
00251
00252 if (result.getLength() > 0)
00253 computer.send(result);
00254 }
00255
00256 void
00257 ChatHandler::handleCommand(ChatClient &computer, const std::string &command)
00258 {
00259 LOG_INFO("Chat: Received unhandled command: " << command);
00260 MessageOut result;
00261 result.writeShort(CPMSG_ERROR);
00262 result.writeByte(CHAT_UNHANDLED_COMMAND);
00263 computer.send(result);
00264 }
00265
00266 void
00267 ChatHandler::warnPlayerAboutBadWords(ChatClient &computer)
00268 {
00269
00270 MessageOut result;
00271 result.writeShort(CPMSG_ERROR);
00272 result.writeByte(CHAT_USING_BAD_WORDS);
00273 computer.send(result);
00274
00275 LOG_INFO(computer.characterName << " says bad words.");
00276 }
00277
00278 void
00279 ChatHandler::handleChatMessage(ChatClient &client, MessageIn &msg)
00280 {
00281 std::string text = msg.readString();
00282
00283
00284 if (!stringFilter->filterContent(text))
00285 {
00286 warnPlayerAboutBadWords(client);
00287 return;
00288 }
00289
00290 short channelId = msg.readShort();
00291 ChatChannel *channel = chatChannelManager->getChannel(channelId);
00292
00293 if (channel)
00294 {
00295 LOG_DEBUG(client.characterName << " says in channel " << channelId
00296 << ": " << text);
00297
00298 MessageOut result(CPMSG_PUBMSG);
00299 result.writeShort(channelId);
00300 result.writeString(client.characterName);
00301 result.writeString(text);
00302 sendInChannel(channel, result);
00303 }
00304
00305
00306 Transaction trans;
00307 trans.mCharacterId = client.characterId;
00308 trans.mAction = TRANS_MSG_PUBLIC;
00309 trans.mMessage = "User said " + text;
00310 storage->addTransaction(trans);
00311 }
00312
00313 void
00314 ChatHandler::handleAnnounceMessage(ChatClient &client, MessageIn &msg)
00315 {
00316 std::string text = msg.readString();
00317
00318 if (!stringFilter->filterContent(text))
00319 {
00320 warnPlayerAboutBadWords(client);
00321 return;
00322 }
00323
00324 if (client.accountLevel == AL_ADMIN || client.accountLevel == AL_GM)
00325 {
00326
00327 LOG_INFO("ANNOUNCE: " << text);
00328 MessageOut result(CPMSG_ANNOUNCEMENT);
00329 result.writeString(text);
00330
00331
00332
00333 sendToEveryone(result);
00334
00335
00336 Transaction trans;
00337 trans.mCharacterId = client.characterId;
00338 trans.mAction = TRANS_MSG_ANNOUNCE;
00339 trans.mMessage = "User announced " + text;
00340 storage->addTransaction(trans);
00341 }
00342 else
00343 {
00344 MessageOut result(CPMSG_ERROR);
00345 result.writeByte(ERRMSG_INSUFFICIENT_RIGHTS);
00346 client.send(result);
00347 LOG_INFO(client.characterName <<
00348 " couldn't make an announcement due to insufficient rights.");
00349 }
00350
00351 }
00352
00353 void
00354 ChatHandler::handlePrivMsgMessage(ChatClient &client, MessageIn &msg)
00355 {
00356 std::string user = msg.readString();
00357 std::string text = msg.readString();
00358
00359 if (!stringFilter->filterContent(text))
00360 {
00361 warnPlayerAboutBadWords(client);
00362 return;
00363 }
00364
00365
00366 sayToPlayer(client, user, text);
00367
00368
00369 Transaction trans;
00370 trans.mCharacterId = client.characterId;
00371 trans.mAction = TRANS_MSG_PRIVATE;
00372 trans.mMessage = "User said " + text;
00373 trans.mMessage.append(" to " + user);
00374 storage->addTransaction(trans);
00375 }
00376
00377 void ChatHandler::handleWhoMessage(ChatClient &client)
00378 {
00379 MessageOut reply(CPMSG_WHO_RESPONSE);
00380
00381 std::map<std::string, ChatClient*>::iterator itr, itr_end;
00382 itr = mPlayerMap.begin();
00383 itr_end = mPlayerMap.end();
00384
00385 while (itr != itr_end)
00386 {
00387 reply.writeString(itr->first);
00388 ++itr;
00389 }
00390
00391 client.send(reply);
00392 }
00393
00394 void ChatHandler::handleEnterChannelMessage(ChatClient &client, MessageIn &msg)
00395 {
00396 MessageOut reply(CPMSG_ENTER_CHANNEL_RESPONSE);
00397
00398 std::string channelName = msg.readString();
00399 std::string givenPassword = msg.readString();
00400 ChatChannel *channel = NULL;
00401 if(chatChannelManager->channelExists(channelName) ||
00402 chatChannelManager->tryNewPublicChannel(channelName))
00403 {
00404 channel = chatChannelManager->getChannel(channelName);
00405 }
00406
00407 if (!channel)
00408 {
00409 reply.writeByte(ERRMSG_INVALID_ARGUMENT);
00410 }
00411 else if (!channel->getPassword().empty() &&
00412 channel->getPassword() != givenPassword)
00413 {
00414
00415 reply.writeByte(ERRMSG_INSUFFICIENT_RIGHTS);
00416 }
00417 else if (!channel->canJoin())
00418 {
00419 reply.writeByte(ERRMSG_INVALID_ARGUMENT);
00420 }
00421 else
00422 {
00423 if (channel->addUser(&client))
00424 {
00425 reply.writeByte(ERRMSG_OK);
00426
00427
00428 reply.writeShort(channel->getId());
00429 reply.writeString(channelName);
00430 reply.writeString(channel->getAnnouncement());
00431 const ChatChannel::ChannelUsers &users = channel->getUserList();
00432
00433 for (ChatChannel::ChannelUsers::const_iterator i = users.begin(),
00434 i_end = users.end();
00435 i != i_end; ++i)
00436 {
00437 reply.writeString((*i)->characterName);
00438 reply.writeString(channel->getUserMode((*i)));
00439 }
00440
00441
00442 warnUsersAboutPlayerEventInChat(channel,
00443 client.characterName,
00444 CHAT_EVENT_NEW_PLAYER);
00445
00446
00447 Transaction trans;
00448 trans.mCharacterId = client.characterId;
00449 trans.mAction = TRANS_CHANNEL_JOIN;
00450 trans.mMessage = "User joined " + channelName;
00451 storage->addTransaction(trans);
00452 }
00453 else
00454 {
00455 reply.writeByte(ERRMSG_FAILURE);
00456 }
00457 }
00458
00459 client.send(reply);
00460 }
00461
00462 void
00463 ChatHandler::handleModeChangeMessage(ChatClient &client, MessageIn &msg)
00464 {
00465 short channelId = msg.readShort();
00466 ChatChannel *channel = chatChannelManager->getChannel(channelId);
00467
00468 if (channelId == 0 || !channel)
00469 {
00470
00471 return;
00472 }
00473
00474 if (channel->getUserMode(&client).find('o') == std::string::npos)
00475 {
00476
00477 return;
00478 }
00479
00480
00481 std::string user = msg.readString();
00482
00483
00484 unsigned char mode = msg.readByte();
00485 channel->setUserMode(getClient(user), mode);
00486
00487
00488 std::stringstream info;
00489 info << client.characterName << ":" << user << ":" << mode;
00490
00491 warnUsersAboutPlayerEventInChat(channel,
00492 info.str(),
00493 CHAT_EVENT_MODE_CHANGE);
00494
00495
00496 Transaction trans;
00497 trans.mCharacterId = client.characterId;
00498 trans.mAction = TRANS_CHANNEL_MODE;
00499 trans.mMessage = "User mode " + mode;
00500 trans.mMessage.append(" set on " + user);
00501 storage->addTransaction(trans);
00502 }
00503
00504 void
00505 ChatHandler::handleKickUserMessage(ChatClient &client, MessageIn &msg)
00506 {
00507 short channelId = msg.readShort();
00508 ChatChannel *channel = chatChannelManager->getChannel(channelId);
00509
00510 if (channelId == 0 || !channel)
00511 {
00512
00513 return;
00514 }
00515
00516 if (channel->getUserMode(&client).find('o') == std::string::npos)
00517 {
00518
00519 return;
00520 }
00521
00522
00523 std::string user = msg.readString();
00524
00525 if (channel->removeUser(getClient(user)))
00526 {
00527 std::stringstream ss;
00528 ss << client.characterName << ":" << user;
00529 warnUsersAboutPlayerEventInChat(channel,
00530 ss.str(),
00531 CHAT_EVENT_KICKED_PLAYER);
00532 }
00533
00534
00535 Transaction trans;
00536 trans.mCharacterId = client.characterId;
00537 trans.mAction = TRANS_CHANNEL_KICK;
00538 trans.mMessage = "User kicked " + user;
00539 storage->addTransaction(trans);
00540 }
00541
00542 void
00543 ChatHandler::handleQuitChannelMessage(ChatClient &client, MessageIn &msg)
00544 {
00545 MessageOut reply(CPMSG_QUIT_CHANNEL_RESPONSE);
00546
00547 short channelId = msg.readShort();
00548 ChatChannel *channel = chatChannelManager->getChannel(channelId);
00549
00550 if (channelId == 0 || !channel)
00551 {
00552 reply.writeByte(ERRMSG_INVALID_ARGUMENT);
00553 }
00554 else if (!channel->removeUser(&client))
00555 {
00556 reply.writeByte(ERRMSG_FAILURE);
00557 }
00558 else
00559 {
00560 reply.writeByte(ERRMSG_OK);
00561 reply.writeShort(channelId);
00562
00563
00564
00565 warnUsersAboutPlayerEventInChat(channel,
00566 client.characterName,
00567 CHAT_EVENT_LEAVING_PLAYER);
00568
00569
00570 Transaction trans;
00571 trans.mCharacterId = client.characterId;
00572 trans.mAction = TRANS_CHANNEL_QUIT;
00573 trans.mMessage = "User left " + channel->getName();
00574 storage->addTransaction(trans);
00575
00576 if(channel->getUserList().empty())
00577 {
00578 chatChannelManager->removeChannel(channel->getId());
00579 }
00580 }
00581
00582 client.send(reply);
00583 }
00584
00585 void
00586 ChatHandler::handleListChannelsMessage(ChatClient &client, MessageIn &msg)
00587 {
00588 MessageOut reply(CPMSG_LIST_CHANNELS_RESPONSE);
00589
00590 std::list<const ChatChannel*> channels =
00591 chatChannelManager->getPublicChannels();
00592
00593 for (std::list<const ChatChannel*>::iterator i = channels.begin(),
00594 i_end = channels.end();
00595 i != i_end; ++i)
00596 {
00597 reply.writeString((*i)->getName());
00598 reply.writeShort((*i)->getUserList().size());
00599 }
00600
00601 client.send(reply);
00602
00603
00604 Transaction trans;
00605 trans.mCharacterId = client.characterId;
00606 trans.mAction = TRANS_CHANNEL_LIST;
00607 trans.mMessage = "";
00608 storage->addTransaction(trans);
00609 }
00610
00611 void
00612 ChatHandler::handleListChannelUsersMessage(ChatClient &client, MessageIn &msg)
00613 {
00614 MessageOut reply(CPMSG_LIST_CHANNELUSERS_RESPONSE);
00615
00616 std::string channelName = msg.readString();
00617 ChatChannel *channel = chatChannelManager->getChannel(channelName);
00618
00619 if (channel)
00620 {
00621 reply.writeString(channel->getName());
00622
00623 const ChatChannel::ChannelUsers &users = channel->getUserList();
00624
00625 for (ChatChannel::ChannelUsers::const_iterator
00626 i = users.begin(), i_end = users.end(); i != i_end; ++i)
00627 {
00628 reply.writeString((*i)->characterName);
00629 reply.writeString(channel->getUserMode((*i)));
00630 }
00631
00632 client.send(reply);
00633 }
00634
00635
00636 Transaction trans;
00637 trans.mCharacterId = client.characterId;
00638 trans.mAction = TRANS_CHANNEL_USERLIST;
00639 trans.mMessage = "";
00640 storage->addTransaction(trans);
00641 }
00642
00643 void
00644 ChatHandler::handleTopicChange(ChatClient &client, MessageIn &msg)
00645 {
00646 short channelId = msg.readShort();
00647 std::string topic = msg.readString();
00648 ChatChannel *channel = chatChannelManager->getChannel(channelId);
00649
00650 if(!guildManager->doesExist(channel->getName()))
00651 {
00652 chatChannelManager->setChannelTopic(channelId, topic);
00653 }
00654 else
00655 {
00656 guildChannelTopicChange(channel, client.characterId, topic);
00657 }
00658
00659
00660 Transaction trans;
00661 trans.mCharacterId = client.characterId;
00662 trans.mAction = TRANS_CHANNEL_TOPIC;
00663 trans.mMessage = "User changed topic to " + topic;
00664 trans.mMessage.append(" in " + channel->getName());
00665 storage->addTransaction(trans);
00666 }
00667
00668 void
00669 ChatHandler::handleDisconnectMessage(ChatClient &client, MessageIn &msg)
00670 {
00671 MessageOut reply(CPMSG_DISCONNECT_RESPONSE);
00672 reply.writeByte(ERRMSG_OK);
00673 chatChannelManager->removeUserFromAllChannels(&client);
00674 guildManager->disconnectPlayer(&client);
00675 client.send(reply);
00676 }
00677
00678 void
00679 ChatHandler::sayToPlayer(ChatClient &computer, const std::string &playerName,
00680 const std::string &text)
00681 {
00682 MessageOut result;
00683 LOG_DEBUG(computer.characterName << " says to " << playerName << ": "
00684 << text);
00685
00686 result.writeShort(CPMSG_PRIVMSG);
00687 result.writeString(computer.characterName);
00688 result.writeString(text);
00689 for (NetComputers::iterator i = clients.begin(), i_end = clients.end();
00690 i != i_end; ++i) {
00691 if (static_cast< ChatClient * >(*i)->characterName == playerName)
00692 {
00693 (*i)->send(result);
00694 break;
00695 }
00696 }
00697 }
00698
00699 void ChatHandler::warnUsersAboutPlayerEventInChat(ChatChannel *channel,
00700 const std::string &info,
00701 char eventId)
00702 {
00703 MessageOut msg(CPMSG_CHANNEL_EVENT);
00704 msg.writeShort(channel->getId());
00705 msg.writeByte(eventId);
00706 msg.writeString(info);
00707 sendInChannel(channel, msg);
00708 }
00709
00710 void ChatHandler::sendInChannel(ChatChannel *channel, MessageOut &msg)
00711 {
00712 const ChatChannel::ChannelUsers &users = channel->getUserList();
00713
00714 for (ChatChannel::ChannelUsers::const_iterator
00715 i = users.begin(), i_end = users.end(); i != i_end; ++i)
00716 {
00717 (*i)->send(msg);
00718 }
00719 }
00720
00721 ChatClient* ChatHandler::getClient(const std::string &name)
00722 {
00723 std::map<std::string, ChatClient*>::iterator itr;
00724 itr = mPlayerMap.find(name);
00725 if (itr != mPlayerMap.end())
00726 {
00727 return itr->second;
00728 }
00729 else
00730 {
00731 return NULL;
00732 }
00733 }