GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/net/tmwa/chatrecv.cpp Lines: 1 152 0.7 %
Date: 2018-07-14 Branches: 2 264 0.8 %

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-2018  The ManaPlus Developers
6
 *
7
 *  This file is part of The ManaPlus Client.
8
 *
9
 *  This program is free software; you can redistribute it and/or modify
10
 *  it under the terms of the GNU General Public License as published by
11
 *  the Free Software Foundation; either version 2 of the License, or
12
 *  any later version.
13
 *
14
 *  This program is distributed in the hope that it will be useful,
15
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 *  GNU General Public License for more details.
18
 *
19
 *  You should have received a copy of the GNU General Public License
20
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
 */
22
23
#include "net/tmwa/chatrecv.h"
24
25
#include "actormanager.h"
26
#include "configuration.h"
27
28
#include "being/localplayer.h"
29
#include "being/playerrelation.h"
30
#include "being/playerrelations.h"
31
32
#include "const/gui/chat.h"
33
34
#include "gui/widgets/tabs/chat/gmtab.h"
35
36
#include "gui/windows/chatwindow.h"
37
#include "gui/windows/shopwindow.h"
38
39
#include "net/serverfeatures.h"
40
41
#include "net/ea/chatrecv.h"
42
43
#include "net/messagein.h"
44
45
#include "net/tmwa/guildmanager.h"
46
47
#include "debug.h"
48
49
namespace TmwAthena
50
{
51
52
void ChatRecv::processChat(Net::MessageIn &msg)
53
{
54
    BLOCK_START("ChatRecv::processChat")
55
    const int chatMsgLength = msg.readInt16("len") - 4;
56
    if (chatMsgLength <= 0)
57
    {
58
        BLOCK_END("ChatRecv::processChat")
59
        return;
60
    }
61
62
    processChatContinue(msg.readRawString(chatMsgLength, "message"));
63
}
64
65
void ChatRecv::processChatContinue(std::string chatMsg)
66
{
67
    const size_t pos = chatMsg.find(" : ", 0);
68
69
    bool allow(true);
70
    if (chatWindow != nullptr)
71
    {
72
        allow = chatWindow->resortChatLog(chatMsg,
73
            ChatMsgType::BY_PLAYER,
74
            GENERAL_CHANNEL,
75
            IgnoreRecord_false,
76
            TryRemoveColors_true);
77
    }
78
79
    const std::string senseStr("You sense the following: ");
80
    if ((actorManager != nullptr) && (chatMsg.find(senseStr) == 0u))
81
    {
82
        actorManager->parseLevels(
83
            chatMsg.substr(senseStr.size()));
84
    }
85
86
    if (pos == std::string::npos &&
87
        !Ea::ChatRecv::mShowMotd &&
88
        Ea::ChatRecv::mSkipping)
89
    {
90
        // skip motd from "new" tmw server
91
        if (Ea::ChatRecv::mMotdTime == 0)
92
        {
93
            Ea::ChatRecv::mMotdTime = cur_time + 1;
94
        }
95
        else if (Ea::ChatRecv::mMotdTime == cur_time ||
96
                 Ea::ChatRecv::mMotdTime < cur_time)
97
        {
98
            Ea::ChatRecv::mSkipping = false;
99
        }
100
        BLOCK_END("ChatRecv::processChat")
101
        return;
102
    }
103
104
    if (pos != std::string::npos)
105
        chatMsg.erase(0, pos + 3);
106
107
    trim(chatMsg);
108
109
    if (localPlayer != nullptr)
110
    {
111
        if ((chatWindow != nullptr || Ea::ChatRecv::mShowMotd) && allow)
112
            localPlayer->setSpeech(chatMsg);
113
    }
114
    BLOCK_END("ChatRecv::processChat")
115
}
116
117
void ChatRecv::processGmChat(Net::MessageIn &msg)
118
{
119
    BLOCK_START("ChatRecv::processChat")
120
    const int chatMsgLength = msg.readInt16("len") - 4;
121
    if (chatMsgLength <= 0)
122
    {
123
        BLOCK_END("ChatRecv::processChat")
124
        return;
125
    }
126
127
    if (localChatTab != nullptr &&
128
        chatWindow != nullptr)
129
    {
130
        std::string chatMsg = msg.readRawString(chatMsgLength, "message");
131
        chatWindow->addGlobalMessage(chatMsg);
132
    }
133
    else
134
    {
135
        msg.readRawString(chatMsgLength, "message");
136
    }
137
    BLOCK_END("ChatRecv::processChat")
138
}
139
140
void ChatRecv::processWhisper(Net::MessageIn &msg)
141
{
142
    BLOCK_START("ChatRecv::processWhisper")
143
    const int chatMsgLength = msg.readInt16("len") - 28;
144
    std::string nick = msg.readString(24, "nick");
145
146
    if (chatMsgLength <= 0)
147
    {
148
        BLOCK_END("ChatRecv::processWhisper")
149
        return;
150
    }
151
152
    processWhisperContinue(nick, msg.readString(chatMsgLength, "message"));
153
}
154
155
void ChatRecv::processWhisperResponse(Net::MessageIn &msg)
156
{
157
    BLOCK_START("ChatRecv::processWhisperResponse")
158
159
    const uint8_t type = msg.readUInt8("response");
160
    Ea::ChatRecv::processWhisperResponseContinue(msg, type);
161
}
162
163
void ChatRecv::processWhisperContinue(const std::string &nick,
164
                                      std::string chatMsg)
165
{
166
    // ignoring future whisper messages
167
    if (chatMsg.find("\302\202G") == 0 || chatMsg.find("\302\202A") == 0)
168
    {
169
        BLOCK_END("ChatRecv::processWhisper")
170
        return;
171
    }
172
    // remove first unicode space if this is may be whisper command.
173
    if (chatMsg.find("\302\202!") == 0)
174
        chatMsg = chatMsg.substr(2);
175
176
    if (nick != "Server")
177
    {
178
        if ((guildManager != nullptr) && GuildManager::getEnableGuildBot()
179
            && nick == "guild" && guildManager->processGuildMessage(chatMsg))
180
        {
181
            BLOCK_END("ChatRecv::processWhisper")
182
            return;
183
        }
184
185
        if (playerRelations.hasPermission(nick, PlayerRelation::WHISPER))
186
        {
187
            const bool tradeBot = config.getBoolValue("tradebot");
188
            const bool showMsg = !config.getBoolValue("hideShopMessages");
189
            if (playerRelations.hasPermission(nick, PlayerRelation::TRADE))
190
            {
191
                if (shopWindow != nullptr)
192
                {   // commands to shop from player
193
                    if (chatMsg.find("!selllist ") == 0)
194
                    {
195
                        if (tradeBot)
196
                        {
197
                            if (showMsg && (chatWindow != nullptr))
198
                            {
199
                                chatWindow->addWhisper(nick,
200
                                    chatMsg,
201
                                    ChatMsgType::BY_OTHER);
202
                            }
203
                            shopWindow->giveList(nick, ShopWindow::SELL);
204
                        }
205
                    }
206
                    else if (chatMsg.find("!buylist ") == 0)
207
                    {
208
                        if (tradeBot)
209
                        {
210
                            if (showMsg && chatWindow != nullptr)
211
                            {
212
                                chatWindow->addWhisper(nick,
213
                                    chatMsg,
214
                                    ChatMsgType::BY_OTHER);
215
                            }
216
                            shopWindow->giveList(nick, ShopWindow::BUY);
217
                        }
218
                    }
219
                    else if (chatMsg.find("!buyitem ") == 0)
220
                    {
221
                        if (showMsg && chatWindow != nullptr)
222
                        {
223
                            chatWindow->addWhisper(nick,
224
                                chatMsg,
225
                                ChatMsgType::BY_OTHER);
226
                        }
227
                        if (tradeBot)
228
                        {
229
                            shopWindow->processRequest(nick, chatMsg,
230
                                ShopWindow::BUY);
231
                        }
232
                    }
233
                    else if (chatMsg.find("!sellitem ") == 0)
234
                    {
235
                        if (showMsg && chatWindow != nullptr)
236
                        {
237
                            chatWindow->addWhisper(nick,
238
                                chatMsg,
239
                                ChatMsgType::BY_OTHER);
240
                        }
241
                        if (tradeBot)
242
                        {
243
                            shopWindow->processRequest(nick, chatMsg,
244
                                ShopWindow::SELL);
245
                        }
246
                    }
247
                    else if (chatMsg.length() > 3
248
                             && chatMsg.find("\302\202") == 0)
249
                    {
250
                        chatMsg = chatMsg.erase(0, 2);
251
                        if (showMsg && chatWindow != nullptr)
252
                        {
253
                            chatWindow->addWhisper(nick,
254
                                chatMsg,
255
                                ChatMsgType::BY_OTHER);
256
                        }
257
                        if (chatMsg.find("B1") == 0 || chatMsg.find("S1") == 0)
258
                            ShopWindow::showList(nick, chatMsg);
259
                    }
260
                    else if (chatWindow != nullptr)
261
                    {
262
                        chatWindow->addWhisper(nick,
263
                            chatMsg,
264
                            ChatMsgType::BY_OTHER);
265
                    }
266
                }
267
                else if (chatWindow != nullptr)
268
                {
269
                    chatWindow->addWhisper(nick,
270
                        chatMsg,
271
                        ChatMsgType::BY_OTHER);
272
                }
273
            }
274
            else
275
            {
276
                if (chatWindow != nullptr &&
277
                    (showMsg ||
278
                    (chatMsg.find("!selllist") != 0 &&
279
                    chatMsg.find("!buylist") != 0)))
280
                {
281
                    chatWindow->addWhisper(nick,
282
                        chatMsg,
283
                        ChatMsgType::BY_OTHER);
284
                }
285
            }
286
        }
287
    }
288
    else if (localChatTab != nullptr)
289
    {
290
        if ((gmChatTab != nullptr) && strStartWith(chatMsg, "[GM] "))
291
        {
292
            chatMsg = chatMsg.substr(5);
293
            const size_t pos = chatMsg.find(": ", 0);
294
            if (pos == std::string::npos)
295
            {
296
                gmChatTab->chatLog(chatMsg,
297
                    ChatMsgType::BY_SERVER,
298
                    IgnoreRecord_false,
299
                    TryRemoveColors_true);
300
            }
301
            else
302
            {
303
                gmChatTab->chatLog(chatMsg.substr(0, pos),
304
                    chatMsg.substr(pos + 2));
305
            }
306
        }
307
        else
308
        {
309
            localChatTab->chatLog(chatMsg,
310
                ChatMsgType::BY_SERVER,
311
                IgnoreRecord_false,
312
                TryRemoveColors_true);
313
        }
314
    }
315
    BLOCK_END("ChatRecv::processWhisper")
316
}
317
318
void ChatRecv::processBeingChat(Net::MessageIn &msg)
319
{
320
    if (actorManager == nullptr)
321
        return;
322
323
    BLOCK_START("ChatRecv::processBeingChat")
324
    const int chatMsgLength = msg.readInt16("len") - 8;
325
    const BeingId beingId = msg.readBeingId("being id");
326
    Being *const being = actorManager->findBeing(beingId);
327
328
    if (chatMsgLength <= 0)
329
    {
330
        BLOCK_END("ChatRecv::processBeingChat")
331
        return;
332
    }
333
334
    std::string chatMsg = msg.readRawString(chatMsgLength, "message");
335
336
    if ((being != nullptr) && being->getType() == ActorType::Player)
337
        being->setTalkTime();
338
339
    const size_t pos = chatMsg.find(" : ", 0);
340
    std::string sender_name = ((pos == std::string::npos)
341
        ? "" : chatMsg.substr(0, pos));
342
343
    if (serverFeatures->haveIncompleteChatMessages())
344
    {
345
        // work around for "new" tmw server
346
        if (being != nullptr)
347
            sender_name = being->getName();
348
        if (sender_name.empty())
349
        {
350
            sender_name = "?" + toString(CAST_S32(beingId));
351
            const std::string name = actorManager->getSeenPlayerById(beingId);
352
            if (!name.empty())
353
                sender_name.append(" ").append(name);
354
        }
355
    }
356
    else if ((being != nullptr) &&
357
             sender_name != being->getName() &&
358
             being->getType() == ActorType::Player)
359
    {
360
        if (!being->getName().empty())
361
            sender_name = being->getName();
362
    }
363
    else
364
    {
365
        chatMsg.erase(0, pos + 3);
366
    }
367
368
    trim(chatMsg);
369
370
    bool allow(true);
371
    // We use getIgnorePlayer instead of ignoringPlayer here
372
    // because ignorePlayer' side effects are triggered
373
    // right below for Being::IGNORE_SPEECH_FLOAT.
374
    if ((playerRelations.checkPermissionSilently(sender_name,
375
        PlayerRelation::SPEECH_LOG) != 0u) &&
376
        (chatWindow != nullptr))
377
    {
378
        allow = chatWindow->resortChatLog(
379
            removeColors(sender_name).append(" : ").append(chatMsg),
380
            ChatMsgType::BY_OTHER,
381
            GENERAL_CHANNEL,
382
            IgnoreRecord_false,
383
            TryRemoveColors_true);
384
    }
385
386
    if (allow &&
387
        (being != nullptr) &&
388
        playerRelations.hasPermission(sender_name,
389
        PlayerRelation::SPEECH_FLOAT))
390
    {
391
        being->setSpeech(chatMsg);
392
    }
393
    BLOCK_END("ChatRecv::processBeingChat")
394
}
395
396
void ChatRecv::processScriptMessage(Net::MessageIn &msg)
397
{
398
    const int sz = msg.readInt16("len") - 5;
399
    msg.readUInt8("message type");
400
    const std::string message = msg.readString(sz, "message");
401
    localChatTab->chatLog(message,
402
        ChatMsgType::BY_SERVER,
403
        IgnoreRecord_false,
404
        TryRemoveColors_true);
405
}
406
407

3
}  // namespace TmwAthena