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

6
}  // namespace TmwAthena