Mana
Loading...
Searching...
No Matches
chathandler.cpp
Go to the documentation of this file.
1/*
2 * The Mana Client
3 * Copyright (C) 2004-2009 The Mana World Development Team
4 * Copyright (C) 2009-2012 The Mana Developers
5 *
6 * This file is part of The Mana Client.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
23
24#include "actorspritemanager.h"
25#include "avatar.h"
26#include "being.h"
27#include "event.h"
28#include "localplayer.h"
29#include "playerrelations.h"
30
31#include "gui/socialwindow.h"
32
34#include "net/tmwa/messagein.h"
35#include "net/tmwa/messageout.h"
36#include "net/tmwa/protocol.h"
37
38#include "utils/gettext.h"
39#include "utils/stringutils.h"
40
41#include <string>
42
44
45namespace TmwAthena {
46
48{
49 static const uint16_t _messages[] = {
57 0
58 };
59 handledMessages = _messages;
60 chatHandler = this;
61}
62
64{
65 Being *being;
66 std::string chatMsg;
67 std::string nick;
68 int chatMsgLength;
69
70 switch (msg.getId())
71 {
73 if (mSentWhispers.empty())
74 nick = "user";
75 else
76 {
77 nick = mSentWhispers.front();
78 mSentWhispers.pop();
79 }
80
81 switch (msg.readInt8())
82 {
83 case 0x00:
84 // Success (don't need to report)
85 break;
86 case 0x01:
87 {
89 event.setString("nick", nick);
90 event.setString("error", strprintf(_("Whisper could "
91 "not be sent, %s is offline."), nick.c_str()));
92 event.trigger(Event::ChatChannel);
93 }
94 break;
95 case 0x02:
96 {
98 event.setString("nick", nick);
99 event.setString("error", strprintf(_("Whisper could "
100 "not be sent, ignored by %s."), nick.c_str()));
101 event.Event::trigger(Event::ChatChannel);
102 }
103 break;
104 }
105 break;
106
107 // Received whisper
108 case SMSG_WHISPER:
109 chatMsgLength = msg.readInt16() - 28;
110 nick = msg.readString(24);
111
112 if (chatMsgLength <= 0)
113 break;
114
115 chatMsg = msg.readString(chatMsgLength);
116
117 // This is a sure sign of some special command, none of which are
118 // supported at the moment.
119 if (chatMsg.compare(0, 3, "\302\202!") == 0)
120 return;
121
122 if (nick != "Server")
123 {
124 // Ignore the shop commands since this client doesn't support
125 // them at the moment.
126 if (chatMsg.find("!selllist ") == 0 ||
127 chatMsg.find("!buylist ") == 0 ||
128 chatMsg.find("!buyitem ") == 0 ||
129 chatMsg.find("!sellitem ") == 0)
130 return;
131
133 {
134 Event event(Event::Whisper);
135 event.setString("nick", nick);
136 event.setString("message", chatMsg);
137 event.trigger(Event::ChatChannel);
138 }
139 }
140 else
141 {
142 serverNotice(chatMsg);
143 }
144
145 break;
146
147 // Received speech from being
148 case SMSG_BEING_CHAT:
149 {
150 chatMsgLength = msg.readInt16() - 8;
151 int beingId = msg.readInt32();
152 being = actorSpriteManager->findBeing(beingId);
153
154 if (!being || chatMsgLength <= 0)
155 break;
156
157 chatMsg = msg.readString(chatMsgLength);
158
159 std::string::size_type pos = chatMsg.find(" : ", 0);
160 std::string sender_name = ((pos == std::string::npos)
161 ? "" : chatMsg.substr(0, pos));
162
163 if (sender_name != being->getName()
164 && being->getType() == Being::PLAYER)
165 {
166 if (!being->getName().empty())
167 sender_name = being->getName();
168 }
169 else
170 {
171 chatMsg.erase(0, pos + 3);
172 }
173
174 int perms;
175
176 if (being->getType() == Being::PLAYER)
177 {
178 perms = player_relations.checkPermissionSilently(sender_name,
180 }
181 else
182 {
186 }
187
188 // This is a sure sign of some special command of manaplus,
189 // none of those are supported at the moment.
190 if (chatMsg.compare(0, 2, "\302\202") == 0)
191 return;
192
193 trim(chatMsg);
194
195 std::string reducedMessage = chatMsg;
196 chatMsg = sender_name;
197 removeColors(chatMsg);
198 chatMsg += " : ";
199 chatMsg += reducedMessage;
200
201 Event event(Event::Being);
202 event.setString("message", chatMsg);
203 event.setString("text", reducedMessage);
204 event.setString("nick", sender_name);
205 event.setInt("beingId", beingId);
206 event.setInt("permissions", perms);
207 event.trigger(Event::ChatChannel);
208
209 break;
210 }
211
212 case SMSG_PLAYER_CHAT:
213 case SMSG_GM_CHAT:
214 {
215 chatMsgLength = msg.readInt16() - 4;
216
217 if (chatMsgLength <= 0)
218 break;
219
220 chatMsg = msg.readString(chatMsgLength);
221
222 if (msg.getId() == SMSG_PLAYER_CHAT)
223 {
224 std::string::size_type pos = chatMsg.find(" : ", 0);
225 std::string mes = chatMsg;
226
227 if (pos != std::string::npos)
228 chatMsg.erase(0, pos + 3);
229
230 trim(chatMsg);
231
232 Event event(Event::Player);
233 event.setString("message", mes);
234 event.setString("text", chatMsg);
235 event.setString("nick", local_player->getName());
236 event.setInt("beingId", local_player->getId());
237 event.setInt("permissions", player_relations.getDefault()
240 event.trigger(Event::ChatChannel);
241 }
242 else
243 {
245 event.setString("message", chatMsg);
246 event.trigger(Event::ChatChannel);
247 }
248 break;
249 }
250
252 {
253 chatMsgLength = msg.readInt16() - 5;
254 if (chatMsgLength <= 0)
255 break;
256
257 msg.readInt8(); // message type
258
259 serverNotice(msg.readString(chatMsgLength));
260 break;
261 }
262
263 case SMSG_ONLINE_LIST:
264 {
265 int length = msg.readInt16();
266 int count = (length - 4) / 31;
267 std::vector<Avatar*> players;
268
269 for (int i = 0; i < count; i++)
270 {
271 msg.readInt32(); // account id
272 std::string nick = msg.readString(24);
273 msg.readInt8(); // level
274 msg.readInt8(); // gm level
275 msg.readInt8(); // gender
276
277 auto *avatar = new Avatar(nick);
278 avatar->setOnline(true);
279 players.push_back(avatar);
280 }
281
283
284 break;
285 }
286
287 }
288}
289
290static void sendChatMessage(const std::string &mes)
291{
293 // Added + 1 in order to let eAthena parse admin commands correctly
294 outMsg.writeInt16(mes.length() + 4 + 1);
295 outMsg.writeString(mes, mes.length() + 1);
296}
297
298void ChatHandler::talk(const std::string &text)
299{
300 const auto loginHandler = static_cast<LoginHandler*>(Net::getLoginHandler());
301
302 if (loginHandler->getServerVersion() >= 0x100408)
303 sendChatMessage(text);
304 else
305 sendChatMessage(local_player->getName() + " : " + text);
306}
307
308void ChatHandler::me(const std::string &text)
309{
310 std::string action = strprintf("*%s*", text.c_str());
311
312 talk(action);
313}
314
315void ChatHandler::privateMessage(const std::string &recipient,
316 const std::string &text)
317{
319 outMsg.writeInt16(text.length() + 28);
320 outMsg.writeString(recipient, 24);
321 outMsg.writeString(text, text.length());
322
323 mSentWhispers.push(recipient);
324}
325
327{
328 serverNotice(_("Channels are not supported!"));
329}
330
331void ChatHandler::enterChannel(const std::string &channel,
332 const std::string &password)
333{
334 serverNotice(_("Channels are not supported!"));
335}
336
337void ChatHandler::quitChannel(int channelId)
338{
339 serverNotice(_("Channels are not supported!"));
340}
341
342void ChatHandler::sendToChannel(int channelId, const std::string &text)
343{
344 serverNotice(_("Channels are not supported!"));
345}
346
347void ChatHandler::userList(const std::string &channel)
348{
349 serverNotice(_("Channels are not supported!"));
350}
351
352void ChatHandler::setChannelTopic(int channelId, const std::string &text)
353{
354 serverNotice(_("Channels are not supported!"));
355}
356
357void ChatHandler::setUserMode(int channelId, const std::string &name, int mode)
358{
359 serverNotice(_("Channels are not supported!"));
360}
361
362void ChatHandler::kickUser(int channelId, const std::string &name)
363{
364 serverNotice(_("Channels are not supported!"));
365}
366
371
372} // namespace TmwAthena
ActorSpriteManager * actorSpriteManager
Definition game.cpp:110
Being * findBeing(int id) const
Returns a specific Being, by id;.
int getId() const
Definition actorsprite.h:63
Definition being.h:65
Type getType() const final
Returns the type of the ActorSprite.
Definition being.h:122
const std::string & getName() const
Returns the name of the being.
Definition being.h:190
Definition event.h:42
@ Announcement
Definition event.h:62
@ Being
Definition event.h:63
@ Whisper
Definition event.h:102
@ Player
Definition event.h:92
@ WhisperError
Definition event.h:103
@ ChatChannel
Definition event.h:49
const uint16_t * handledMessages
unsigned int getDefault() const
Retrieves the default permissions.
bool hasPermission(Being *being, unsigned int flags)
Tests whether the player in question is being ignored for any of the actions in the specified flags.
unsigned int checkPermissionSilently(const std::string &player_name, unsigned int flags)
Determines whether the player in question is being ignored, filtered by the specified flags.
void setPlayersOnline(const std::vector< Avatar * > &players)
void requestOnlineList() override
void channelList() override
void userList(const std::string &channel) override
void privateMessage(const std::string &recipient, const std::string &text) override
void setUserMode(int channelId, const std::string &name, int mode) override
void kickUser(int channelId, const std::string &name) override
void handleMessage(MessageIn &msg) override
void me(const std::string &text) override
std::queue< std::string > mSentWhispers
Definition chathandler.h:71
void quitChannel(int channelId) override
void sendToChannel(int channelId, const std::string &text) override
void setChannelTopic(int channelId, const std::string &text) override
void enterChannel(const std::string &channel, const std::string &password) override
void talk(const std::string &text) override
Used for parsing an incoming message from eAthena.
Definition messagein.h:35
std::string readString(int length=-1)
Reads a string.
uint16_t readInt16()
Reads an unsigned 16-bit integer from the message.
Definition messagein.cpp:57
uint8_t readInt8()
Reads an unsigned 8-bit integer from the message.
Definition messagein.cpp:46
uint16_t getId() const
Returns the message ID.
Definition messagein.h:42
uint32_t readInt32()
Reads an unsigned 32-bit integer from the message.
Definition messagein.cpp:69
Used for building an outgoing message to eAthena.
Definition messageout.h:35
void writeInt16(uint16_t value)
Writes an unsigned 16-bit integer to the message.
void writeString(const std::string &string, int length=-1)
Writes a string.
void serverNotice(const std::string &message)
Definition event.h:319
SocialWindow * socialWindow
Definition game.cpp:108
#define _(s)
Definition gettext.h:38
LocalPlayer * local_player
Net::ChatHandler * chatHandler
Definition net.cpp:48
ManaServ::LoginHandler * loginHandler
Definition net.cpp:51
LoginHandler * getLoginHandler()
Definition net.cpp:95
Warning: buffers and other variables are shared, so there can be only one connection active at a time...
@ SMSG_ONLINE_LIST
Definition protocol.h:297
@ CMSG_ONLINE_LIST
Definition protocol.h:296
@ CMSG_CHAT_WHISPER
Definition protocol.h:181
@ SMSG_WHISPER
Definition protocol.h:182
@ SMSG_BEING_CHAT
Definition protocol.h:174
@ SMSG_PLAYER_CHAT
Definition protocol.h:175
@ SMSG_SCRIPT_MESSAGE
Definition protocol.h:305
@ SMSG_GM_CHAT
Definition protocol.h:184
@ SMSG_WHISPER_RESPONSE
Definition protocol.h:183
@ CMSG_CHAT_MESSAGE
Definition protocol.h:173
PlayerRelationsManager player_relations
std::string strprintf(char const *format,...)
A safe version of sprintf that returns a std::string of the result.
std::string & trim(std::string &str)
Trims spaces off the end and the beginning of the given string.
std::string & removeColors(std::string &msg)
Removes colors from a string.