GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/net/tmwa/chatrecv.cpp Lines: 2 156 1.3 %
Date: 2018-12-09 Branches: 2 270 0.7 %

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 "utils/gettext.h"
48
49
#include "debug.h"
50
51
namespace TmwAthena
52
{
53
54
namespace ChatRecv
55
{
56
1
    std::string mShopRequestName;
57
}  // namespace ChatRecv
58
59
void ChatRecv::processChat(Net::MessageIn &msg)
60
{
61
    BLOCK_START("ChatRecv::processChat")
62
    const int chatMsgLength = msg.readInt16("len") - 4;
63
    if (chatMsgLength <= 0)
64
    {
65
        BLOCK_END("ChatRecv::processChat")
66
        return;
67
    }
68
69
    processChatContinue(msg.readRawString(chatMsgLength, "message"));
70
}
71
72
void ChatRecv::processChatContinue(std::string chatMsg)
73
{
74
    const size_t pos = chatMsg.find(" : ", 0);
75
76
    bool allow(true);
77
    if (chatWindow != nullptr)
78
    {
79
        allow = chatWindow->resortChatLog(chatMsg,
80
            ChatMsgType::BY_PLAYER,
81
            GENERAL_CHANNEL,
82
            IgnoreRecord_false,
83
            TryRemoveColors_true);
84
    }
85
86
    const std::string senseStr("You sense the following: ");
87
    if ((actorManager != nullptr) && (chatMsg.find(senseStr) == 0U))
88
    {
89
        actorManager->parseLevels(
90
            chatMsg.substr(senseStr.size()));
91
    }
92
93
    if (pos == std::string::npos &&
94
        !Ea::ChatRecv::mShowMotd &&
95
        Ea::ChatRecv::mSkipping)
96
    {
97
        // skip motd from "new" tmw server
98
        if (Ea::ChatRecv::mMotdTime == 0)
99
        {
100
            Ea::ChatRecv::mMotdTime = cur_time + 1;
101
        }
102
        else if (Ea::ChatRecv::mMotdTime == cur_time ||
103
                 Ea::ChatRecv::mMotdTime < cur_time)
104
        {
105
            Ea::ChatRecv::mSkipping = false;
106
        }
107
        BLOCK_END("ChatRecv::processChat")
108
        return;
109
    }
110
111
    if (pos != std::string::npos)
112
        chatMsg.erase(0, pos + 3);
113
114
    trim(chatMsg);
115
116
    if (localPlayer != nullptr)
117
    {
118
        if ((chatWindow != nullptr || Ea::ChatRecv::mShowMotd) && allow)
119
            localPlayer->setSpeech(chatMsg);
120
    }
121
    BLOCK_END("ChatRecv::processChat")
122
}
123
124
void ChatRecv::processGmChat(Net::MessageIn &msg)
125
{
126
    BLOCK_START("ChatRecv::processChat")
127
    const int chatMsgLength = msg.readInt16("len") - 4;
128
    if (chatMsgLength <= 0)
129
    {
130
        BLOCK_END("ChatRecv::processChat")
131
        return;
132
    }
133
134
    if (localChatTab != nullptr &&
135
        chatWindow != nullptr)
136
    {
137
        std::string chatMsg = msg.readRawString(chatMsgLength, "message");
138
        chatWindow->addGlobalMessage(chatMsg);
139
    }
140
    else
141
    {
142
        msg.readRawString(chatMsgLength, "message");
143
    }
144
    BLOCK_END("ChatRecv::processChat")
145
}
146
147
void ChatRecv::processWhisper(Net::MessageIn &msg)
148
{
149
    BLOCK_START("ChatRecv::processWhisper")
150
    const int chatMsgLength = msg.readInt16("len") - 28;
151
    std::string nick = msg.readString(24, "nick");
152
153
    if (chatMsgLength <= 0)
154
    {
155
        BLOCK_END("ChatRecv::processWhisper")
156
        return;
157
    }
158
159
    processWhisperContinue(nick, msg.readString(chatMsgLength, "message"));
160
}
161
162
void ChatRecv::processWhisperResponse(Net::MessageIn &msg)
163
{
164
    BLOCK_START("ChatRecv::processWhisperResponse")
165
166
    const uint8_t type = msg.readUInt8("response");
167
    Ea::ChatRecv::processWhisperResponseContinue(msg, type);
168
}
169
170
void ChatRecv::processWhisperContinue(const std::string &nick,
171
                                      std::string chatMsg)
172
{
173
    // ignoring future whisper messages
174
    if (chatMsg.find("\302\202G") == 0 || chatMsg.find("\302\202A") == 0)
175
    {
176
        BLOCK_END("ChatRecv::processWhisper")
177
        return;
178
    }
179
    // remove first unicode space if this is may be whisper command.
180
    if (chatMsg.find("\302\202!") == 0)
181
        chatMsg = chatMsg.substr(2);
182
183
    if (nick != "Server")
184
    {
185
        if ((guildManager != nullptr) && GuildManager::getEnableGuildBot()
186
            && nick == "guild" && guildManager->processGuildMessage(chatMsg))
187
        {
188
            BLOCK_END("ChatRecv::processWhisper")
189
            return;
190
        }
191
192
        if (playerRelations.hasPermission(nick, PlayerRelation::WHISPER))
193
        {
194
            const bool tradeBot = config.getBoolValue("tradebot");
195
            const bool showMsg = !config.getBoolValue("hideShopMessages");
196
            if (playerRelations.hasPermission(nick, PlayerRelation::TRADE))
197
            {
198
                if (shopWindow != nullptr)
199
                {   // commands to shop from player
200
                    if (chatMsg.find("!selllist ") == 0)
201
                    {
202
                        if (tradeBot)
203
                        {
204
                            if (showMsg && (chatWindow != nullptr))
205
                            {
206
                                chatWindow->addWhisper(nick,
207
                                    chatMsg,
208
                                    ChatMsgType::BY_OTHER);
209
                            }
210
                            shopWindow->giveList(nick, ShopWindow::SELL);
211
                        }
212
                    }
213
                    else if (chatMsg.find("!buylist ") == 0)
214
                    {
215
                        if (tradeBot)
216
                        {
217
                            if (showMsg && chatWindow != nullptr)
218
                            {
219
                                chatWindow->addWhisper(nick,
220
                                    chatMsg,
221
                                    ChatMsgType::BY_OTHER);
222
                            }
223
                            shopWindow->giveList(nick, ShopWindow::BUY);
224
                        }
225
                    }
226
                    else if (chatMsg.find("!buyitem ") == 0)
227
                    {
228
                        if (showMsg && chatWindow != nullptr)
229
                        {
230
                            chatWindow->addWhisper(nick,
231
                                chatMsg,
232
                                ChatMsgType::BY_OTHER);
233
                        }
234
                        if (tradeBot)
235
                        {
236
                            shopWindow->processRequest(nick, chatMsg,
237
                                ShopWindow::BUY);
238
                        }
239
                    }
240
                    else if (chatMsg.find("!sellitem ") == 0)
241
                    {
242
                        if (showMsg && chatWindow != nullptr)
243
                        {
244
                            chatWindow->addWhisper(nick,
245
                                chatMsg,
246
                                ChatMsgType::BY_OTHER);
247
                        }
248
                        if (tradeBot)
249
                        {
250
                            shopWindow->processRequest(nick, chatMsg,
251
                                ShopWindow::SELL);
252
                        }
253
                    }
254
                    else if (chatMsg.length() > 3
255
                             && chatMsg.find("\302\202") == 0)
256
                    {
257
                        chatMsg = chatMsg.erase(0, 2);
258
                        if (mShopRequestName != nick)
259
                        {
260
                            debugMsg(strprintf(
261
                                // TRANSLATORS: message about spam player
262
                                _("Detected spam from: %s"),
263
                                nick.c_str()));
264
                            BLOCK_END("ChatRecv::processWhisper")
265
                            return;
266
                        }
267
                        mShopRequestName.clear();
268
                        if (showMsg && chatWindow != nullptr)
269
                        {
270
                            chatWindow->addWhisper(nick,
271
                                chatMsg,
272
                                ChatMsgType::BY_OTHER);
273
                        }
274
                        if (chatMsg.find("B1") == 0 || chatMsg.find("S1") == 0)
275
                            ShopWindow::showList(nick, chatMsg);
276
                    }
277
                    else if (chatWindow != nullptr)
278
                    {
279
                        chatWindow->addWhisper(nick,
280
                            chatMsg,
281
                            ChatMsgType::BY_OTHER);
282
                    }
283
                }
284
                else if (chatWindow != nullptr)
285
                {
286
                    chatWindow->addWhisper(nick,
287
                        chatMsg,
288
                        ChatMsgType::BY_OTHER);
289
                }
290
            }
291
            else
292
            {
293
                if (chatWindow != nullptr &&
294
                    (showMsg ||
295
                    (chatMsg.find("!selllist") != 0 &&
296
                    chatMsg.find("!buylist") != 0)))
297
                {
298
                    chatWindow->addWhisper(nick,
299
                        chatMsg,
300
                        ChatMsgType::BY_OTHER);
301
                }
302
            }
303
        }
304
    }
305
    else if (localChatTab != nullptr)
306
    {
307
        if ((gmChatTab != nullptr) && strStartWith(chatMsg, "[GM] "))
308
        {
309
            chatMsg = chatMsg.substr(5);
310
            const size_t pos = chatMsg.find(": ", 0);
311
            if (pos == std::string::npos)
312
            {
313
                gmChatTab->chatLog(chatMsg,
314
                    ChatMsgType::BY_SERVER,
315
                    IgnoreRecord_false,
316
                    TryRemoveColors_true);
317
            }
318
            else
319
            {
320
                gmChatTab->chatLog(chatMsg.substr(0, pos),
321
                    chatMsg.substr(pos + 2));
322
            }
323
        }
324
        else
325
        {
326
            localChatTab->chatLog(chatMsg,
327
                ChatMsgType::BY_SERVER,
328
                IgnoreRecord_false,
329
                TryRemoveColors_true);
330
        }
331
    }
332
    BLOCK_END("ChatRecv::processWhisper")
333
}
334
335
void ChatRecv::processBeingChat(Net::MessageIn &msg)
336
{
337
    if (actorManager == nullptr)
338
        return;
339
340
    BLOCK_START("ChatRecv::processBeingChat")
341
    const int chatMsgLength = msg.readInt16("len") - 8;
342
    const BeingId beingId = msg.readBeingId("being id");
343
    Being *const being = actorManager->findBeing(beingId);
344
345
    if (chatMsgLength <= 0)
346
    {
347
        BLOCK_END("ChatRecv::processBeingChat")
348
        return;
349
    }
350
351
    std::string chatMsg = msg.readRawString(chatMsgLength, "message");
352
353
    if ((being != nullptr) && being->getType() == ActorType::Player)
354
        being->setTalkTime();
355
356
    const size_t pos = chatMsg.find(" : ", 0);
357
    std::string sender_name = ((pos == std::string::npos)
358
        ? "" : chatMsg.substr(0, pos));
359
360
    if (serverFeatures->haveIncompleteChatMessages())
361
    {
362
        // work around for "new" tmw server
363
        if (being != nullptr)
364
            sender_name = being->getName();
365
        if (sender_name.empty())
366
        {
367
            sender_name = "?" + toString(CAST_S32(beingId));
368
            const std::string name = actorManager->getSeenPlayerById(beingId);
369
            if (!name.empty())
370
                sender_name.append(" ").append(name);
371
        }
372
    }
373
    else if ((being != nullptr) &&
374
             sender_name != being->getName() &&
375
             being->getType() == ActorType::Player)
376
    {
377
        if (!being->getName().empty())
378
            sender_name = being->getName();
379
    }
380
    else
381
    {
382
        chatMsg.erase(0, pos + 3);
383
    }
384
385
    trim(chatMsg);
386
387
    bool allow(true);
388
    // We use getIgnorePlayer instead of ignoringPlayer here
389
    // because ignorePlayer' side effects are triggered
390
    // right below for Being::IGNORE_SPEECH_FLOAT.
391
    if ((playerRelations.checkPermissionSilently(sender_name,
392
        PlayerRelation::SPEECH_LOG) != 0U) &&
393
        (chatWindow != nullptr))
394
    {
395
        allow = chatWindow->resortChatLog(
396
            removeColors(sender_name).append(" : ").append(chatMsg),
397
            ChatMsgType::BY_OTHER,
398
            GENERAL_CHANNEL,
399
            IgnoreRecord_false,
400
            TryRemoveColors_true);
401
    }
402
403
    if (allow &&
404
        (being != nullptr) &&
405
        playerRelations.hasPermission(sender_name,
406
        PlayerRelation::SPEECH_FLOAT))
407
    {
408
        being->setSpeech(chatMsg);
409
    }
410
    BLOCK_END("ChatRecv::processBeingChat")
411
}
412
413
void ChatRecv::processScriptMessage(Net::MessageIn &msg)
414
{
415
    const int sz = msg.readInt16("len") - 5;
416
    msg.readUInt8("message type");
417
    const std::string message = msg.readString(sz, "message");
418
    localChatTab->chatLog(message,
419
        ChatMsgType::BY_SERVER,
420
        IgnoreRecord_false,
421
        TryRemoveColors_true);
422
}
423
424

3
}  // namespace TmwAthena