GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/gui/windows/whoisonline.cpp Lines: 68 442 15.4 %
Date: 2021-03-17 Branches: 28 526 5.3 %

Line Branch Exec Source
1
/*
2
 *  The ManaPlus Client
3
 *  Copyright (C) 2009  The Mana World Development Team
4
 *  Copyright (C) 2011-2019  The ManaPlus Developers
5
 *  Copyright (C) 2009-2021  Andrei Karas
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 "gui/windows/whoisonline.h"
24
25
#include "actormanager.h"
26
#include "configuration.h"
27
#include "guild.h"
28
#include "party.h"
29
#ifdef TMWA_SUPPORT
30
#include "settings.h"
31
#endif  // TMWA_SUPPORT
32
33
#include "gui/onlineplayer.h"
34
#include "gui/popupmanager.h"
35
#include "gui/viewport.h"
36
37
#include "gui/popups/popupmenu.h"
38
39
#include "gui/windows/chatwindow.h"
40
#include "gui/windows/setupwindow.h"
41
#include "gui/windows/socialwindow.h"
42
43
#include "gui/widgets/button.h"
44
#include "gui/widgets/scrollarea.h"
45
#include "gui/widgets/staticbrowserbox.h"
46
47
#include "being/beingflag.h"
48
#include "being/localplayer.h"
49
#include "being/playerrelations.h"
50
51
#ifdef TMWA_SUPPORT
52
#include "net/download.h"
53
#endif  // TMWA_SUPPORT
54
#include "net/packetlimiter.h"
55
#include "net/playerhandler.h"
56
#include "net/serverfeatures.h"
57
58
#ifdef TMWA_SUPPORT
59
#include "resources/db/groupdb.h"
60
#endif  // TMWA_SUPPORT
61
62
#include "utils/foreach.h"
63
#include "utils/gettext.h"
64
#include "utils/sdlhelper.h"
65
66
#ifdef TMWA_SUPPORT
67
#include "net/net.h"
68
#else  // TMWA_SUPPORT
69
#include <curl/curl.h>
70
#endif  // TMWA_SUPPORT
71
72
#include "debug.h"
73
74
#ifdef free
75
#undef free
76
#endif  // free
77
78
#ifdef malloc
79
#undef malloc
80
#endif  // malloc
81
82
WhoIsOnline *whoIsOnline = nullptr;
83
84
namespace
85
{
86
    class NameFunctuator final
87
    {
88
        public:
89
            A_DEFAULT_COPY(NameFunctuator)
90
91
            bool operator()(const OnlinePlayer *left,
92
                            const OnlinePlayer *right) const
93
            {
94
                return (compareStrI(left->getNick(), right->getNick()) < 0);
95
            }
96
    } nameCompare;
97
}  // namespace
98
99
1
WhoIsOnline::WhoIsOnline() :
100
    // TRANSLATORS: who is online window name
101
1
    Window(_("Who Is Online - Updating"),
102
        Modal_false,
103
        nullptr,
104
        "whoisonline.xml"),
105
    mUpdateTimer(0),
106
    mThread(nullptr),
107
    mMemoryBuffer(nullptr),
108
1
    mCurlError(new char[CURL_ERROR_SIZE]),
109
    mBrowserBox(new StaticBrowserBox(this, Opaque_true,
110

1
        "onlinebrowserbox.xml")),
111
    mScrollArea(new ScrollArea(this,
112

2
        mBrowserBox, Opaque_false, std::string())),
113
    // TRANSLATORS: who is online. button.
114

2
    mUpdateButton(new Button(this, _("Update"), "update", BUTTON_SKIN, this)),
115
    mOnlinePlayers(),
116
    mOnlineNicks(),
117
    mFriends(),
118
    mNeutral(),
119
    mDisregard(),
120
    mEnemy(),
121
    mDownloadedBytes(0),
122
    mDownloadStatus(UPDATE_LIST),
123
    mDownloadComplete(true),
124
    mAllowUpdate(true),
125
    mShowLevel(false),
126

4
    mUpdateOnlineList(config.getBoolValue("updateOnlineList")),
127
    mGroupFriends(true),
128
#ifdef TMWA_SUPPORT
129
1
    mWebList(Net::getNetworkType() == ServerType::TMWATHENA),
130
#endif
131


30
    mServerSideList(serverFeatures->haveServerOnlineList())
132
{
133
1
    mCurlError[0] = 0;
134
5
    setWindowName("WhoIsOnline");
135
1
}
136
137
1
void WhoIsOnline::postInit()
138
{
139
1
    Window::postInit();
140
1
    const int h = 350;
141
1
    const int w = 200;
142
1
    setDefaultSize(w, h, ImagePosition::CENTER, 0, 0);
143
144
1
    setVisible(Visible_false);
145
1
    setCloseButton(true);
146
1
    setResizable(true);
147
1
    setStickyButtonLock(true);
148
2
    setSaveVisible(true);
149
150
1
    if (setupWindow != nullptr)
151
        setupWindow->registerWindowForReset(this);
152
153
2
    mUpdateButton->setEnabled(false);
154
1
    mUpdateButton->setDimension(Rect(5, 5, w - 10, 20 + 5));
155
156
2
    mBrowserBox->setOpaque(Opaque_false);
157
1
    mScrollArea->setDimension(Rect(5, 20 + 10, w - 10, h - 10 - 30));
158
1
    mScrollArea->setSize(w - 10, h - 10 - 30);
159
2
    mScrollArea->setSelectable(false);
160
1
    mBrowserBox->setLinkHandler(this);
161
162
1
    add(mUpdateButton);
163
1
    add(mScrollArea);
164
165
2
    setLocationRelativeTo(getParent());
166
167
1
    loadWindowState();
168
2
    enableVisibleSound(true);
169
170
1
    download();
171
172
2
    widgetResized(Event(nullptr));
173
4
    config.addListener("updateOnlineList", this);
174
4
    config.addListener("groupFriends", this);
175
4
    mGroupFriends = config.getBoolValue("groupFriends");
176
1
}
177
178
12
WhoIsOnline::~WhoIsOnline()
179
{
180
1
    config.removeListeners(this);
181
    CHECKLISTENERS
182
183
1
    SDL::WaitThread(mThread);
184
1
    mThread = nullptr;
185
1
    free(mMemoryBuffer);
186
1
    mMemoryBuffer = nullptr;
187
188
    // Remove possibly leftover temporary download
189
1
    delete []mCurlError;
190
191
3
    FOR_EACH (std::set<OnlinePlayer*>::iterator, itd, mOnlinePlayers)
192
        delete *itd;
193
2
    mOnlinePlayers.clear();
194
2
    mOnlineNicks.clear();
195
2
}
196
197
void WhoIsOnline::handleLink(const std::string& link, MouseEvent *event)
198
{
199
    if ((event == nullptr) || event->getButton() == MouseButton::LEFT)
200
    {
201
        if (chatWindow != nullptr)
202
        {
203
            const std::string text = decodeLinkText(link);
204
            if (config.getBoolValue("whispertab"))
205
            {
206
                chatWindow->localChatInput("/q " + text);
207
            }
208
            else
209
            {
210
                chatWindow->addInputText(
211
                    std::string("/w \"").append(text).append("\" "),
212
                    true);
213
            }
214
        }
215
    }
216
    else if (event->getButton() == MouseButton::RIGHT)
217
    {
218
        if ((localPlayer != nullptr) && link == localPlayer->getName())
219
            return;
220
221
        if (popupMenu != nullptr)
222
        {
223
            if (actorManager != nullptr)
224
            {
225
                const std::string text = decodeLinkText(link);
226
                Being *const being = actorManager->findBeingByName(
227
                    text, ActorType::Player);
228
229
                if ((being != nullptr) && (popupManager != nullptr))
230
                {
231
                    popupMenu->showPopup(viewport->mMouseX,
232
                        viewport->mMouseY,
233
                        being);
234
                    return;
235
                }
236
            }
237
            popupMenu->showPlayerPopup(link);
238
        }
239
    }
240
}
241
242
void WhoIsOnline::updateWindow(size_t numOnline)
243
{
244
    // Set window caption
245
    // TRANSLATORS: who is online window name
246
    setCaption(_("Who Is Online - ") + toString(CAST_U32(numOnline)));
247
248
    // List the online people
249
    std::sort(mFriends.begin(), mFriends.end(), nameCompare);
250
    std::sort(mNeutral.begin(), mNeutral.end(), nameCompare);
251
    std::sort(mDisregard.begin(), mDisregard.end(), nameCompare);
252
    bool addedFromSection(false);
253
    FOR_EACH (STD_VECTOR<OnlinePlayer*>::const_iterator, it, mFriends)
254
    {
255
        mBrowserBox->addRow((*it)->getText(), false);
256
        addedFromSection = true;
257
    }
258
    if (addedFromSection == true)
259
    {
260
        mBrowserBox->addRow("---", false);
261
        addedFromSection = false;
262
    }
263
    FOR_EACH (STD_VECTOR<OnlinePlayer*>::const_iterator, it, mEnemy)
264
    {
265
        mBrowserBox->addRow((*it)->getText(), false);
266
        addedFromSection = true;
267
    }
268
    if (addedFromSection == true)
269
    {
270
        mBrowserBox->addRow("---", false);
271
        addedFromSection = false;
272
    }
273
    FOR_EACH (STD_VECTOR<OnlinePlayer*>::const_iterator, it, mNeutral)
274
    {
275
        mBrowserBox->addRow((*it)->getText(), false);
276
        addedFromSection = true;
277
    }
278
    if (addedFromSection == true && !mDisregard.empty())
279
        mBrowserBox->addRow("---", false);
280
281
    FOR_EACH (STD_VECTOR<OnlinePlayer*>::const_iterator, it, mDisregard)
282
        mBrowserBox->addRow((*it)->getText(), false);
283
284
    if (mScrollArea->getVerticalMaxScroll() <
285
        mScrollArea->getVerticalScrollAmount())
286
    {
287
        mScrollArea->setVerticalScrollAmount(
288
            mScrollArea->getVerticalMaxScroll());
289
    }
290
    mBrowserBox->updateHeight();
291
}
292
293
void WhoIsOnline::handlerPlayerRelation(const std::string &nick,
294
                                        OnlinePlayer *const player)
295
{
296
    if (player == nullptr)
297
        return;
298
    switch (playerRelations.getRelation(nick))
299
    {
300
        case Relation::NEUTRAL:
301
        default:
302
            setNeutralColor(player);
303
            mNeutral.push_back(player);
304
            break;
305
306
        case Relation::FRIEND:
307
            player->setText("2");
308
            if (mGroupFriends)
309
                mFriends.push_back(player);
310
            else
311
                mNeutral.push_back(player);
312
            break;
313
314
        case Relation::DISREGARDED:
315
        case Relation::BLACKLISTED:
316
            player->setText("8");
317
            mDisregard.push_back(player);
318
            break;
319
320
        case Relation::ENEMY2:
321
            player->setText("1");
322
            mEnemy.push_back(player);
323
            break;
324
325
        case Relation::IGNORED:
326
        case Relation::ERASED:
327
            // Ignore the ignored.
328
            break;
329
    }
330
}
331
332
void WhoIsOnline::loadList(const STD_VECTOR<OnlinePlayer*> &list)
333
{
334
    mBrowserBox->clearRows();
335
    const size_t numOnline = list.size();
336
337
    FOR_EACH (std::set<OnlinePlayer*>::iterator, itd, mOnlinePlayers)
338
        delete *itd;
339
    mOnlinePlayers.clear();
340
    mOnlineNicks.clear();
341
342
    mShowLevel = config.getBoolValue("showlevel");
343
344
    FOR_EACH (STD_VECTOR<OnlinePlayer*>::const_iterator, it, list)
345
    {
346
        OnlinePlayer *player = *it;
347
        const std::string nick = player->getNick();
348
        mOnlinePlayers.insert(player);
349
        mOnlineNicks.insert(nick);
350
351
        if (!mShowLevel)
352
            player->setLevel(0);
353
354
        handlerPlayerRelation(nick, player);
355
    }
356
357
    updateWindow(numOnline);
358
    if (!mOnlineNicks.empty())
359
    {
360
        if (chatWindow != nullptr)
361
            chatWindow->updateOnline(mOnlineNicks);
362
        if (socialWindow != nullptr)
363
            socialWindow->updateActiveList();
364
        if (actorManager != nullptr)
365
            actorManager->updateSeenPlayers(mOnlineNicks);
366
    }
367
    updateSize();
368
    mFriends.clear();
369
    mNeutral.clear();
370
    mDisregard.clear();
371
    mEnemy.clear();
372
}
373
374
#ifdef TMWA_SUPPORT
375
void WhoIsOnline::loadWebList()
376
{
377
    if (mMemoryBuffer == nullptr)
378
        return;
379
380
    // Reallocate and include terminating 0 character
381
    mMemoryBuffer = static_cast<char*>(
382
        realloc(mMemoryBuffer, mDownloadedBytes + 1));
383
    if (mMemoryBuffer == nullptr)
384
        return;
385
386
    mMemoryBuffer[mDownloadedBytes] = '\0';
387
388
    mBrowserBox->clearRows();
389
    bool listStarted(false);
390
    std::string lineStr;
391
    size_t numOnline(0U);
392
393
    // Tokenize and add each line separately
394
    char *line = strtok(mMemoryBuffer, "\n");
395
    const std::string gmText("(GM)");
396
    const std::string gmText2("(gm)");
397
398
    FOR_EACH (std::set<OnlinePlayer*>::iterator, itd, mOnlinePlayers)
399
        delete *itd;
400
401
    mOnlinePlayers.clear();
402
    mOnlineNicks.clear();
403
404
    mShowLevel = config.getBoolValue("showlevel");
405
406
    while (line != nullptr)
407
    {
408
        std::string nick;
409
        lineStr = line;
410
        trim(lineStr);
411
        if (listStarted == true)
412
        {
413
            if (lineStr.find(" users are online.") == std::string::npos)
414
            {
415
                if (lineStr.length() > 24)
416
                {
417
                    nick = lineStr.substr(0, 24);
418
                    lineStr = lineStr.substr(25);
419
                }
420
                else
421
                {
422
                    nick = lineStr;
423
                    lineStr.clear();
424
                }
425
                trim(nick);
426
427
                bool isGM(false);
428
                size_t pos = lineStr.find(gmText, 0);
429
                if (pos != std::string::npos)
430
                {
431
                    lineStr = lineStr.substr(pos + gmText.length());
432
                    isGM = true;
433
                }
434
                else
435
                {
436
                    pos = lineStr.find(gmText2, 0);
437
                    if (pos != std::string::npos)
438
                    {
439
                        lineStr = lineStr.substr(pos + gmText.length());
440
                        isGM = true;
441
                    }
442
                }
443
444
                trim(lineStr);
445
                pos = lineStr.find('/', 0);
446
447
                if (pos != std::string::npos)
448
                    lineStr = lineStr.substr(0, pos);
449
450
                int level = 0;
451
                if (!lineStr.empty())
452
                    level = atoi(lineStr.c_str());
453
454
                if (actorManager != nullptr)
455
                {
456
                    Being *const being = actorManager->findBeingByName(
457
                        nick, ActorType::Player);
458
                    if (being != nullptr)
459
                    {
460
                        if (level > 0)
461
                        {
462
                            being->setLevel(level);
463
                            being->updateName();
464
                        }
465
                        else
466
                        {
467
                            if (being->getLevel() > 1)
468
                                level = being->getLevel();
469
                        }
470
                    }
471
                }
472
473
                if (!mShowLevel)
474
                    level = 0;
475
476
                OnlinePlayer *const player = new OnlinePlayer(nick,
477
                    CAST_U8(255), level,
478
                    Gender::UNSPECIFIED, -1, -1);
479
                mOnlinePlayers.insert(player);
480
                mOnlineNicks.insert(nick);
481
482
                if (isGM)
483
                    player->setIsGM(true);
484
485
                numOnline++;
486
                handlerPlayerRelation(nick, player);
487
            }
488
        }
489
        else if (lineStr.find("------------------------------")
490
                 != std::string::npos)
491
        {
492
            listStarted = true;
493
        }
494
        line = strtok(nullptr, "\n");
495
    }
496
497
    updateWindow(numOnline);
498
    mBrowserBox->updateHeight();
499
500
    // Free the memory buffer now that we don't need it anymore
501
    free(mMemoryBuffer);
502
    mMemoryBuffer = nullptr;
503
    mFriends.clear();
504
    mNeutral.clear();
505
    mDisregard.clear();
506
    mEnemy.clear();
507
}
508
509
size_t WhoIsOnline::memoryWrite(void *restrict ptr,
510
                                size_t size,
511
                                size_t nmemb,
512
                                FILE *restrict stream)
513
{
514
    if (stream == nullptr)
515
        return 0;
516
517
    WhoIsOnline *restrict const wio =
518
        reinterpret_cast<WhoIsOnline *restrict>(stream);
519
    const size_t totalMem = size * nmemb;
520
    wio->mMemoryBuffer = static_cast<char*>(realloc(wio->mMemoryBuffer,
521
        CAST_SIZE(wio->mDownloadedBytes) + totalMem));
522
    if (wio->mMemoryBuffer != nullptr)
523
    {
524
        memcpy(&(wio->mMemoryBuffer[wio->mDownloadedBytes]), ptr, totalMem);
525
        wio->mDownloadedBytes += CAST_S32(totalMem);
526
    }
527
528
    return totalMem;
529
}
530
531
int WhoIsOnline::downloadThread(void *ptr)
532
{
533
    int attempts = 0;
534
    WhoIsOnline *const wio = reinterpret_cast<WhoIsOnline *>(ptr);
535
    if (wio == nullptr)
536
        return 0;
537
    CURLcode res;
538
    const std::string url(settings.onlineListUrl + "/online.txt");
539
540
    while (attempts < 1 && !wio->mDownloadComplete)
541
    {
542
        CURL *curl = curl_easy_init();
543
        if (curl != nullptr)
544
        {
545
            if (!wio->mAllowUpdate)
546
            {
547
                curl_easy_cleanup(curl);
548
                curl = nullptr;
549
                break;
550
            }
551
            wio->mDownloadedBytes = 0;
552
            curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
553
            curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1);
554
            curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,
555
                                   &WhoIsOnline::memoryWrite);
556
            curl_easy_setopt(curl, CURLOPT_WRITEDATA, ptr);
557
558
            curl_easy_setopt(curl,
559
                CURLOPT_USERAGENT,
560
                settings.userAgent.c_str());
561
562
            curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, wio->mCurlError);
563
            curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
564
            curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1);
565
            curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, ptr);
566
567
#if LIBCURL_VERSION_NUM >= 0x070a00
568
            curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
569
#endif  // LIBCURL_VERSION_NUM >= 0x070a00
570
            curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 7);
571
            curl_easy_setopt(curl, CURLOPT_TIMEOUT, 30);
572
            Net::Download::addHeaders(curl);
573
            Net::Download::addProxy(curl);
574
            Net::Download::secureCurl(curl);
575
            Net::Download::addCommonFlags(curl);
576
577
            // Make sure the resources2.txt and news.txt aren't cached,
578
            // in order to always get the latest version.
579
            curl_slist *pHeaders = nullptr;
580
            pHeaders = curl_slist_append(
581
                pHeaders, "pragma: no-cache");
582
            pHeaders = curl_slist_append(pHeaders,
583
                "Cache-Control: no-cache");
584
            curl_easy_setopt(curl, CURLOPT_HTTPHEADER, pHeaders);
585
586
            if ((res = curl_easy_perform(curl)) != 0)
587
            {
588
                wio->mDownloadStatus = UPDATE_ERROR;
589
                PRAGMA45(GCC diagnostic push)
590
                PRAGMA45(GCC diagnostic ignored "-Wswitch-enum")
591
                switch (res)
592
                {
593
                    case CURLE_COULDNT_CONNECT:
594
                    default:
595
                        std::cerr << "curl error "
596
                                  << CAST_U32(res) << ": "
597
                                  << wio->mCurlError << " host: "
598
                                  << url.c_str() << std::endl;
599
                    break;
600
                }
601
                PRAGMA45(GCC diagnostic pop)
602
                attempts++;
603
                curl_easy_cleanup(curl);
604
                curl_slist_free_all(pHeaders);
605
                curl = nullptr;
606
                continue;
607
            }
608
609
            curl_easy_cleanup(curl);
610
            curl_slist_free_all(pHeaders);
611
612
            // It's stored in memory, we're done
613
            wio->mDownloadComplete = true;
614
        }
615
        if (!wio->mAllowUpdate)
616
            break;
617
        attempts++;
618
    }
619
620
    if (!wio->mDownloadComplete)
621
        wio->mDownloadStatus = UPDATE_ERROR;
622
    return 0;
623
}
624
#endif  // TMWA_SUPPORT
625
626
1
void WhoIsOnline::download()
627
{
628
1
    if (mServerSideList)
629
    {
630
        if (PacketLimiter::limitPackets(PacketType::PACKET_ONLINELIST))
631
            playerHandler->requestOnlineList();
632
    }
633
#ifdef TMWA_SUPPORT
634
1
    else if (mWebList)
635
    {
636
        mDownloadComplete = true;
637
        SDL::WaitThread(mThread);
638
        mThread = nullptr;
639
        mDownloadComplete = false;
640
        mThread = SDL::createThread(&WhoIsOnline::downloadThread,
641
            "whoisonline", this);
642
        if (mThread == nullptr)
643
            mDownloadStatus = UPDATE_ERROR;
644
    }
645
#endif  // TMWA_SUPPORT
646
1
}
647
648
void WhoIsOnline::logic()
649
{
650
    BLOCK_START("WhoIsOnline::logic")
651
    mScrollArea->logic();
652
    BLOCK_END("WhoIsOnline::logic")
653
}
654
655
void WhoIsOnline::slowLogic()
656
{
657
    if (!mAllowUpdate)
658
        return;
659
660
    BLOCK_START("WhoIsOnline::slowLogic")
661
    if (mUpdateTimer == 0)
662
        mUpdateTimer = cur_time;
663
664
    const double timeDiff = difftime(cur_time, mUpdateTimer);
665
    const int timeLimit = isWindowVisible() ? 20 : 120;
666
667
    if (mUpdateOnlineList && timeDiff >= timeLimit
668
        && mDownloadStatus != UPDATE_LIST)
669
    {
670
        if (mDownloadComplete == true)
671
        {
672
            // TRANSLATORS: who is online window name
673
            setCaption(_("Who Is Online - Updating"));
674
            mUpdateTimer = 0;
675
            mDownloadStatus = UPDATE_LIST;
676
            download();
677
        }
678
    }
679
680
#ifdef TMWA_SUPPORT
681
    switch (mDownloadStatus)
682
    {
683
        case UPDATE_ERROR:
684
            logger->assertLog("Failed to fetch the online list:");
685
            if (mCurlError != nullptr)
686
                logger->assertLog("%s", mCurlError);
687
            mDownloadStatus = UPDATE_COMPLETE;
688
            // TRANSLATORS: who is online window name
689
            setCaption(_("Who Is Online - error"));
690
            mUpdateButton->setEnabled(true);
691
            mUpdateTimer = cur_time + 240;
692
            mDownloadComplete = true;
693
            updateSize();
694
            break;
695
        case UPDATE_LIST:
696
            if (mDownloadComplete == true)
697
            {
698
                loadWebList();
699
                mDownloadStatus = UPDATE_COMPLETE;
700
                mUpdateButton->setEnabled(true);
701
                mUpdateTimer = 0;
702
                updateSize();
703
                if (!mOnlineNicks.empty())
704
                {
705
                    if (chatWindow != nullptr)
706
                        chatWindow->updateOnline(mOnlineNicks);
707
                    if (socialWindow != nullptr)
708
                        socialWindow->updateActiveList();
709
                    if (actorManager != nullptr)
710
                        actorManager->updateSeenPlayers(mOnlineNicks);
711
                }
712
            }
713
            break;
714
        case UPDATE_COMPLETE:
715
        default:
716
            break;
717
    }
718
#endif  // TMWA_SUPPORT
719
720
    BLOCK_END("WhoIsOnline::slowLogic")
721
}
722
723
void WhoIsOnline::action(const ActionEvent &event)
724
{
725
    if (event.getId() == "update")
726
    {
727
#ifdef TMWA_SUPPORT
728
        if (!mServerSideList)
729
        {
730
            if (mDownloadStatus == UPDATE_COMPLETE)
731
            {
732
                mUpdateTimer = cur_time - 20;
733
                if (mUpdateButton != nullptr)
734
                    mUpdateButton->setEnabled(false);
735
                // TRANSLATORS: who is online window name
736
                setCaption(_("Who Is Online - Update"));
737
                SDL::WaitThread(mThread);
738
                mThread = nullptr;
739
                mDownloadComplete = true;
740
            }
741
        }
742
        else
743
#endif  // TMWA_SUPPORT
744
        {
745
            if (PacketLimiter::limitPackets(PacketType::PACKET_ONLINELIST))
746
            {
747
                mUpdateTimer = cur_time;
748
                playerHandler->requestOnlineList();
749
            }
750
        }
751
    }
752
}
753
754
1
void WhoIsOnline::widgetResized(const Event &event)
755
{
756
2
    Window::widgetResized(event);
757
2
    updateSize();
758
1
}
759
760
2
void WhoIsOnline::updateSize()
761
{
762
4
    const Rect area = getChildrenArea();
763
2
    if (mUpdateButton != nullptr)
764
2
        mUpdateButton->setWidth(area.width - 10);
765
766
2
    if (mScrollArea != nullptr)
767
2
        mScrollArea->setSize(area.width - 10, area.height - 10 - 30);
768
2
}
769
770
const std::string WhoIsOnline::prepareNick(const std::string &restrict nick,
771
                                           const int level,
772
                                           const std::string &restrict
773
                                           color) const
774
{
775
    const std::string text = encodeLinkText(nick);
776
    if (mShowLevel && level > 1)
777
    {
778
        return strprintf("@@%s|##%s%s (%d)@@", text.c_str(),
779
            color.c_str(), text.c_str(), level);
780
    }
781
    return strprintf("@@%s|##%s%s@@", text.c_str(),
782
        color.c_str(), text.c_str());
783
}
784
785
void WhoIsOnline::optionChanged(const std::string &name)
786
{
787
    if (name == "updateOnlineList")
788
        mUpdateOnlineList = config.getBoolValue("updateOnlineList");
789
    else if (name == "groupFriends")
790
        mGroupFriends = config.getBoolValue("groupFriends");
791
}
792
793
void WhoIsOnline::setNeutralColor(OnlinePlayer *const player)
794
{
795
    if (player == nullptr)
796
        return;
797
798
    if ((actorManager != nullptr) && (localPlayer != nullptr))
799
    {
800
        const std::string &nick = player->getNick();
801
        if (nick == localPlayer->getName())
802
        {
803
            player->setText("s");
804
            return;
805
        }
806
        if (localPlayer->isInParty())
807
        {
808
            const Party *const party = localPlayer->getParty();
809
            if (party != nullptr)
810
            {
811
                if (party->getMember(nick) != nullptr)
812
                {
813
                    player->setText("P");
814
                    return;
815
                }
816
            }
817
        }
818
819
        const Being *const being = actorManager->findBeingByName(nick,
820
            ActorType::Player);
821
        if (being != nullptr)
822
        {
823
            const Guild *const guild2 = localPlayer->getGuild();
824
            if (guild2 != nullptr)
825
            {
826
                const Guild *const guild1 = being->getGuild();
827
                if (guild1 != nullptr)
828
                {
829
                    if (guild1->getId() == guild2->getId()
830
                        || (guild2->getMember(nick) != nullptr))
831
                    {
832
                        player->setText("U");
833
                        return;
834
                    }
835
                }
836
                else if (guild2->isMember(nick))
837
                {
838
                    player->setText("U");
839
                    return;
840
                }
841
            }
842
        }
843
        const Guild *const guild3 = Guild::getGuild(1);
844
        if ((guild3 != nullptr) && guild3->isMember(nick))
845
        {
846
            player->setText("U");
847
            return;
848
        }
849
    }
850
    player->setText("0");
851
}
852
853
void WhoIsOnline::getPlayerNames(StringVect &names)
854
{
855
    names.clear();
856
    FOR_EACH (std::set<std::string>::const_iterator, it, mOnlineNicks)
857
        names.push_back(*it);
858
}
859
860
void OnlinePlayer::setText(std::string color)
861
{
862
    mText.clear();
863
864
    if (mStatus != 255 && (actorManager != nullptr))
865
    {
866
        Being *const being = actorManager->findBeingByName(
867
            mNick, ActorType::Player);
868
        if (being != nullptr)
869
        {
870
            being->setState(mStatus);
871
            // for now highlight versions > 3
872
            if (mVersion > 3)
873
                being->setAdvanced(true);
874
        }
875
    }
876
877
#ifdef TMWA_SUPPORT
878
    if (mGroup != -1 && GroupDb::getShowBadge(mGroup))
879
    {
880
        const std::string &name = GroupDb::getName(mGroup);
881
        mText.append(strprintf("(%s) ", name.c_str()));
882
    }
883
    else
884
#endif
885
    {
886
        if ((mStatus != 255 && ((mStatus & BeingFlag::GM) != 0)) || mIsGM)
887
            mText.append("(GM) ");
888
    }
889
890
    if (mLevel > 0)
891
        mText.append(strprintf("%d", mLevel));
892
893
    if (mGender == Gender::FEMALE)
894
        mText.append("\u2640");
895
    else if (mGender == Gender::MALE)
896
        mText.append("\u2642");
897
898
#ifdef TMWA_SUPPORT
899
    if (mGroup != -1 && GroupDb::getHighlightName(mGroup) && color == "0")
900
        color = "2";
901
#endif
902
903
    if (mStatus > 0 && mStatus != 255)
904
    {
905
        if ((mStatus & BeingFlag::SHOP) != 0)
906
            mText.append("$");
907
        if ((mStatus & BeingFlag::AWAY) != 0)
908
        {
909
            // TRANSLATORS: this away status writed in player nick
910
            mText.append(_("A"));
911
        }
912
        if ((mStatus & BeingFlag::INACTIVE) != 0)
913
        {
914
            // TRANSLATORS: this inactive status writed in player nick
915
            mText.append(_("I"));
916
        }
917
918
        if (((mStatus & BeingFlag::GM) != 0) && color == "0")
919
            color = "2";
920
    }
921
    else if (mIsGM && color == "0")
922
    {
923
        color = "2";
924
    }
925
926
    if (mVersion > 0)
927
        mText.append(strprintf(" - %d", mVersion));
928
929
    const std::string text = encodeLinkText(mNick);
930
    mText = strprintf("@@%s|##%s%s %s@@", text.c_str(), color.c_str(),
931
        text.c_str(), mText.c_str());
932

3
}