ManaPlus
chathandler.cpp
Go to the documentation of this file.
1 /*
2  * The ManaPlus Client
3  * Copyright (C) 2004-2009 The Mana World Development Team
4  * Copyright (C) 2009-2010 The Mana Developers
5  * Copyright (C) 2011-2019 The ManaPlus Developers
6  * Copyright (C) 2019-2021 Andrei Karas
7  *
8  * This file is part of The ManaPlus Client.
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program. If not, see <http://www.gnu.org/licenses/>.
22  */
23 
25 
26 #include "being/localplayer.h"
27 
28 #include "net/serverfeatures.h"
29 
30 #include "net/ea/chatrecv.h"
31 
32 #include "net/eathena/chatrecv.h"
33 #include "net/eathena/messageout.h"
35 
36 #include "resources/chatobject.h"
37 
38 #include "utils/stringutils.h"
39 
40 #include "debug.h"
41 
42 extern int packetVersion;
43 
44 namespace EAthena
45 {
46 
48  Ea::ChatHandler()
49 {
50  chatHandler = this;
51 }
52 
54 {
55  chatHandler = nullptr;
56 }
57 
58 void ChatHandler::talk(const std::string &restrict text) const
59 {
60  if (localPlayer == nullptr)
61  return;
62 
63  const std::string mes = std::string(localPlayer->getName()).append(
64  " : ").append(text);
65 
66  createOutPacket(CMSG_CHAT_MESSAGE);
67  if (packetVersion >= 20151001)
68  {
69  outMsg.writeInt16(CAST_S16(mes.length() + 4), "len");
70  outMsg.writeString(mes, CAST_S32(mes.length()), "message");
71  }
72  else
73  {
74  // Added + 1 in order to let eAthena parse admin commands correctly
75  outMsg.writeInt16(CAST_S16(mes.length() + 4 + 1), "len");
76  outMsg.writeString(mes, CAST_S32(mes.length() + 1), "message");
77  }
78 }
79 
80 void ChatHandler::talkRaw(const std::string &mes) const
81 {
82  createOutPacket(CMSG_CHAT_MESSAGE);
83  outMsg.writeInt16(CAST_S16(mes.length() + 4), "len");
84  outMsg.writeString(mes, CAST_S32(mes.length()), "message");
85 }
86 
87 void ChatHandler::privateMessage(const std::string &restrict recipient,
88  const std::string &restrict text) const
89 {
90  createOutPacket(CMSG_CHAT_WHISPER);
91  if (packetVersion >= 20151001)
92  {
93  outMsg.writeInt16(CAST_S16(text.length() + 28), "len");
94  outMsg.writeString(recipient, 24, "recipient nick");
95  outMsg.writeString(text, CAST_S32(text.length()), "message");
96  }
97  else
98  {
99  outMsg.writeInt16(CAST_S16(text.length() + 28 + 1), "len");
100  outMsg.writeString(recipient, 24, "recipient nick");
101  outMsg.writeString(text, CAST_S32(text.length()), "message");
102  outMsg.writeInt8(0, "null char");
103  }
104  Ea::ChatRecv::mSentWhispers.push(recipient);
105 }
106 
107 void ChatHandler::channelMessage(const std::string &restrict channel,
108  const std::string &restrict text) const
109 {
110  privateMessage(channel, text);
111 }
112 
113 void ChatHandler::who() const
114 {
115  createOutPacket(CMSG_WHO_REQUEST);
116 }
117 
118 void ChatHandler::sendRaw(const std::string &args) const
119 {
120  std::string line = args;
121  std::string str;
122  MessageOut *outMsg = nullptr;
123 
124  if (line.empty())
125  return;
126 
127  size_t pos = line.find(' ');
128  if (pos != std::string::npos)
129  {
130  str = line.substr(0, pos);
131 
132  const int16_t id = CAST_S16(parseNumber(str));
133  outMsg = new MessageOut(id);
134  outMsg->writeInt16(id, "packet id");
135  line = line.substr(pos + 1);
136  pos = line.find(' ');
137  }
138  else
139  {
140  const int16_t id = CAST_S16(parseNumber(line));
141  outMsg = new MessageOut(id);
142  outMsg->writeInt16(id, "packet id");
143  delete outMsg;
144  return;
145  }
146 
147  while (pos != std::string::npos)
148  {
149  str = line.substr(0, pos);
150  processRaw(*outMsg, str);
151  line = line.substr(pos + 1);
152  pos = line.find(' ');
153  }
154  if (!line.empty())
155  processRaw(*outMsg, line);
156  delete outMsg;
157 }
158 
160  const std::string &restrict line)
161 {
162  if (line.size() < 2)
163  return;
164 
165  const uint32_t i = parseNumber(line.substr(1));
166  switch (tolower(line[0]))
167  {
168  case 'b':
169  {
170  outMsg.writeInt8(CAST_U8(i), "raw");
171  break;
172  }
173  case 'w':
174  {
175  outMsg.writeInt16(CAST_S16(i), "raw");
176  break;
177  }
178  case 'l':
179  {
180  outMsg.writeInt32(CAST_S32(i), "raw");
181  break;
182  }
183  default:
184  break;
185  }
186 }
187 
189 {
190  createOutPacket(CMSG_IGNORE_ALL);
191  outMsg.writeInt8(0, "flag");
192 }
193 
195 {
196  createOutPacket(CMSG_IGNORE_ALL);
197  outMsg.writeInt8(1, "flag");
198 }
199 
200 
201 void ChatHandler::ignore(const std::string &nick) const
202 {
203  createOutPacket(CMSG_IGNORE_NICK);
204  outMsg.writeString(nick, 24, "nick");
205  outMsg.writeInt8(0, "flag");
206 }
207 
208 void ChatHandler::unIgnore(const std::string &nick) const
209 {
210  createOutPacket(CMSG_IGNORE_NICK);
211  outMsg.writeString(nick, 24, "nick");
212  outMsg.writeInt8(1, "flag");
213 }
214 
216 {
217  createOutPacket(CMSG_REQUEST_IGNORE_LIST);
218 }
219 
220 void ChatHandler::createChatRoom(const std::string &title,
221  const std::string &password,
222  const int limit,
223  const bool isPublic) const
224 {
225  createOutPacket(CMSG_CREAYE_CHAT_ROOM);
226  outMsg.writeInt16(CAST_S16(
227  7 + 8 + 36), "len");
228  outMsg.writeInt16(CAST_S16(limit), "limit");
229  outMsg.writeInt8(CAST_S8(isPublic ? 1 : 0), "public");
230  outMsg.writeString(password, 8, "password");
231  outMsg.writeString(title, 36, "title");
232  ChatRecv::mChatRoom = title;
233 }
234 
235 void ChatHandler::battleTalk(const std::string &text) const
236 {
237  if (localPlayer == nullptr)
238  return;
239 
240  const std::string mes = std::string(localPlayer->getName()).append(
241  " : ").append(text);
242 
243  createOutPacket(CMSG_BATTLE_CHAT_MESSAGE);
244  if (packetVersion >= 20151001)
245  {
246  outMsg.writeInt16(CAST_S16(mes.length() + 4), "len");
247  outMsg.writeString(mes, CAST_S32(mes.length()), "message");
248  }
249  else
250  {
251  // Added + 1 in order to let eAthena parse admin commands correctly
252  outMsg.writeInt16(CAST_S16(mes.length() + 4 + 1), "len");
253  outMsg.writeString(mes, CAST_S32(mes.length() + 1), "message");
254  }
255 }
256 
257 void ChatHandler::joinChat(const ChatObject *const chat,
258  const std::string &password) const
259 {
260  if (chat == nullptr)
261  return;
262 
263  createOutPacket(CMSG_CHAT_ROOM_JOIN);
264  outMsg.writeInt32(chat->chatId, "chat id");
265  outMsg.writeString(password, 8, "password");
266 }
267 
268 void ChatHandler::joinChannel(const std::string &channel) const
269 {
271  {
272  createOutPacket(CMSG_CHAT_JOIN_CHANNEL);
273  outMsg.writeString(channel, 24, "channel name");
274  }
275  else
276  {
277  channelMessage(channel, "\302\202\302");
278  }
279 }
280 
281 void ChatHandler::partChannel(const std::string &channel) const
282 {
284  {
285  createOutPacket(CMSG_CHAT_PART_CHANNEL);
286  outMsg.writeString(channel, 24, "channel name");
287  }
288 }
289 
290 void ChatHandler::talkPet(const std::string &restrict text) const
291 {
292  if (text.empty())
293  return;
294  std::string msg = text;
295  if (msg.size() > 500)
296  msg = msg.substr(0, 500);
297  const size_t sz = msg.size();
298 
299  createOutPacket(CMSG_PET_TALK);
300  outMsg.writeInt16(CAST_S16(sz + 4 + 1), "len");
301  outMsg.writeString(msg, CAST_S32(sz), "message");
302  outMsg.writeInt8(0, "zero byte");
303 }
304 
306 {
307  createOutPacket(CMSG_LEAVE_CHAT_ROOM);
308 }
309 
310 void ChatHandler::setChatRoomOptions(const int limit,
311  const bool isPublic,
312  const std::string &password,
313  const std::string &title) const
314 {
315  createOutPacket(CMSG_SET_CHAT_ROOM_OPTIONS);
316  const int sz = CAST_S32(title.size());
317  outMsg.writeInt16(CAST_S16(15 + sz), "len");
318  outMsg.writeInt16(CAST_S16(limit), "limit");
319  outMsg.writeInt8(CAST_S8(isPublic ? 1 : 0), "type");
320  outMsg.writeString(password, 8, "password");
321  outMsg.writeString(title, sz, "title");
322 }
323 
324 void ChatHandler::setChatRoomOwner(const std::string &nick) const
325 {
326  createOutPacket(CMSG_SET_CHAT_ROOM_OWNER);
327  outMsg.writeInt32(0, "role (unused)");
328  outMsg.writeString(nick, 24, "nick");
329 }
330 
331 void ChatHandler::kickFromChatRoom(const std::string &nick) const
332 {
333  createOutPacket(CMSG_KICK_FROM_CHAT_ROOM);
334  outMsg.writeString(nick, 24, "nick");
335 }
336 
337 } // namespace EAthena
#define CAST_S8
Definition: cast.h:26
#define CAST_S16
Definition: cast.h:28
#define CAST_S32
Definition: cast.h:30
#define CAST_U8
Definition: cast.h:27
Net::ChatHandler * chatHandler
Definition: net.cpp:86
const std::string & getName() const
Definition: being.h:232
void ignoreAll() const
void sendRaw(const std::string &args) const
void privateMessage(const std::string &recipient, const std::string &text) const
Definition: chathandler.cpp:87
void setChatRoomOwner(const std::string &nick) const
void unIgnore(const std::string &nick) const
void requestIgnoreList() const
void ignore(const std::string &nick) const
void talk(const std::string &text) const
Definition: chathandler.cpp:58
void setChatRoomOptions(const int limit, const bool isPublic, const std::string &password, const std::string &title) const
void leaveChatRoom() const
void battleTalk(const std::string &text) const
void talkPet(const std::string &text) const
void joinChannel(const std::string &channel) const
static void processRaw(MessageOut &outMsg, const std::string &line)
void partChannel(const std::string &channel) const
void talkRaw(const std::string &text) const
Definition: chathandler.cpp:80
void kickFromChatRoom(const std::string &nick) const
void channelMessage(const std::string &channel, const std::string &text) const
void unIgnoreAll() const
void joinChat(const ChatObject *const chat, const std::string &password) const
void createChatRoom(const std::string &title, const std::string &password, const int limit, const bool isPublic) const
void writeInt16(const int16_t value, const char *const str)
Definition: messageout.cpp:71
virtual bool haveJoinChannel() const =0
int packetVersion
Definition: client.cpp:125
#define restrict
Definition: localconsts.h:165
LocalPlayer * localPlayer
#define createOutPacket(name)
Definition: messageout.h:37
bool msg(InputEvent &event)
Definition: chat.cpp:39
std::string mChatRoom
Definition: chatrecv.cpp:61
WhisperQueue mSentWhispers
Definition: chatrecv.cpp:49
Net::ServerFeatures * serverFeatures
Definition: net.cpp:101
uint32_t parseNumber(const std::string &str)
int chatId
Definition: chatobject.h:47