GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/net/eathena/chathandler.cpp Lines: 1 150 0.7 %
Date: 2021-03-17 Branches: 0 210 0.0 %

Line Branch Exec Source
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
24
#include "net/eathena/chathandler.h"
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"
34
#include "net/eathena/protocolout.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
47
ChatHandler::ChatHandler() :
48
    Ea::ChatHandler()
49
{
50
    chatHandler = this;
51
}
52
53
ChatHandler::~ChatHandler()
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
159
void ChatHandler::processRaw(MessageOut &restrict outMsg,
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
188
void ChatHandler::ignoreAll() const
189
{
190
    createOutPacket(CMSG_IGNORE_ALL);
191
    outMsg.writeInt8(0, "flag");
192
}
193
194
void ChatHandler::unIgnoreAll() const
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
215
void ChatHandler::requestIgnoreList() const
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
{
270
    if (serverFeatures->haveJoinChannel())
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
{
283
    if (serverFeatures->haveJoinChannel())
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
305
void ChatHandler::leaveChatRoom() const
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
2
}  // namespace EAthena