GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/gui/windows/serverdialog.cpp Lines: 206 453 45.5 %
Date: 2021-03-17 Branches: 255 754 33.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-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 "gui/windows/serverdialog.h"
25
26
#include "chatlogger.h"
27
#include "client.h"
28
#include "configuration.h"
29
#include "main.h"
30
#include "settings.h"
31
32
#include "net/download.h"
33
34
#include "fs/paths.h"
35
36
#include "gui/widgets/checkbox.h"
37
#include "gui/widgets/createwidget.h"
38
#include "gui/widgets/desktop.h"
39
#include "gui/windows/editserverdialog.h"
40
#include "gui/windows/logindialog.h"
41
#include "gui/windows/serverinfowindow.h"
42
43
#include "gui/widgets/button.h"
44
#include "gui/widgets/label.h"
45
#include "gui/widgets/layout.h"
46
#include "gui/widgets/serverslistbox.h"
47
#include "gui/widgets/scrollarea.h"
48
49
#include "utils/delete2.h"
50
#include "utils/foreach.h"
51
#include "utils/langs.h"
52
53
#include "debug.h"
54
55
#ifdef WIN32
56
#undef ERROR
57
#endif  // WIN32
58
59
static const int MAX_SERVERLIST = 15;
60
61
static std::string serverTypeToString(const ServerTypeT type)
62
{
63
    switch (type)
64
    {
65
        case ServerType::TMWATHENA:
66
#ifdef TMWA_SUPPORT
67
            return "TmwAthena";
68
#else  // TMWA_SUPPORT
69
70
            return "";
71
#endif  // TMWA_SUPPORT
72
73
        case ServerType::EATHENA:
74
            return "eAthena";
75
        case ServerType::EVOL2:
76
            return "Evol2";
77
        default:
78
        case ServerType::UNKNOWN:
79
            return "";
80
    }
81
}
82
83
static uint16_t defaultPortForServerType(const ServerTypeT type)
84
{
85

30
    switch (type)
86
    {
87
        default:
88
        case ServerType::EATHENA:
89
        case ServerType::EVOL2:
90
            return 6900;
91
        case ServerType::UNKNOWN:
92
        case ServerType::TMWATHENA:
93
            return 6901;
94
    }
95
}
96
97
2
ServerDialog::ServerDialog(ServerInfo *const serverInfo,
98
2
                           const std::string &dir) :
99
    // TRANSLATORS: servers dialog name
100
2
    Window(_("Choose Your Server"), Modal_false, nullptr, "server.xml"),
101
    ActionListener(),
102
    KeyListener(),
103
    SelectionListener(),
104
    mMutex(),
105
    mServers(ServerInfos()),
106
    mDir(dir),
107

4
    mDescription(new Label(this, std::string())),
108
    // TRANSLATORS: servers dialog button
109

4
    mQuitButton(new Button(this, _("Quit"), "quit", BUTTON_SKIN, this)),
110
    // TRANSLATORS: servers dialog button
111
2
    mConnectButton(new Button(this, _("Connect"), "connect",
112

2
        BUTTON_SKIN, this)),
113
    // TRANSLATORS: servers dialog button
114

4
    mAddEntryButton(new Button(this, _("Add"), "addEntry", BUTTON_SKIN, this)),
115
    // TRANSLATORS: servers dialog button
116
2
    mEditEntryButton(new Button(this, _("Edit"), "editEntry",
117

2
        BUTTON_SKIN, this)),
118
    // TRANSLATORS: servers dialog button
119

4
    mDeleteButton(new Button(this, _("Delete"), "remove", BUTTON_SKIN, this)),
120
    // TRANSLATORS: servers dialog button
121

4
    mLoadButton(new Button(this, _("Load"), "load", BUTTON_SKIN, this)),
122
    // TRANSLATORS: servers dialog button
123

4
    mInfoButton(new Button(this, _("Info"), "info", BUTTON_SKIN, this)),
124

2
    mServersListModel(new ServersListModel(&mServers, this)),
125

2
    mServersList(CREATEWIDGETR(ServersListBox, this, mServersListModel)),
126
    mDownload(nullptr),
127
    mServerInfo(serverInfo),
128
    mPersistentIPCheckBox(nullptr),
129
    mDownloadProgress(-1.0F),
130








130
    mDownloadStatus(ServerDialogDownloadStatus::UNKNOWN)
131
{
132
2
    if (isSafeMode)
133
    {
134
        // TRANSLATORS: servers dialog name
135
        setCaption(_("Choose Your Server  *** SAFE MODE ***"));
136
    }
137
#ifdef USE_OPENGL
138

8
    else if (config.getIntValue("opengl") == RENDER_SOFTWARE)
139
    {
140
        // TRANSLATORS: servers dialog name
141
10
        setCaption(_("Choose Your Server  *** SOFTWARE RENDER MODE ***"));
142
    }
143
#endif  // USE_OPENGL
144
145
10
    setWindowName("ServerDialog");
146
147
2
    setCloseButton(true);
148
149
2
    mPersistentIPCheckBox = new CheckBox(this,
150
        // TRANSLATORS: servers dialog checkbox
151
2
        _("Use same ip for game sub servers"),
152

8
        config.getBoolValue("usePersistentIP"),
153


16
        this, "persitent ip");
154
155
2
    loadCustomServers();
156
157
2
    mServersList->addMouseListener(this);
158
159
2
    ScrollArea *const usedScroll = new ScrollArea(this, mServersList,
160

8
        fromBool(getOptionBool("showbackground", false), Opaque),
161

10
        "server_background.xml");
162
2
    usedScroll->setHorizontalScrollPolicy(ScrollArea::SHOW_NEVER);
163
164
2
    mServersList->addSelectionListener(this);
165
2
    usedScroll->setVerticalScrollAmount(0);
166
167
4
    place(0, 0, usedScroll, 8, 5).setPadding(3);
168
2
    place(0, 5, mDescription, 8, 1);
169
2
    place(0, 6, mPersistentIPCheckBox, 8, 1);
170
2
    place(0, 7, mInfoButton, 1, 1);
171
2
    place(1, 7, mAddEntryButton, 1, 1);
172
2
    place(2, 7, mEditEntryButton, 1, 1);
173
2
    place(3, 7, mLoadButton, 1, 1);
174
2
    place(4, 7, mDeleteButton, 1, 1);
175
2
    place(6, 7, mQuitButton, 1, 1);
176
2
    place(7, 7, mConnectButton, 1, 1);
177
178
    // Make sure the list has enough height
179

2
    getLayout().setRowHeight(0, 80);
180
181
    // Do this manually instead of calling reflowLayout so we can enforce a
182
    // minimum width.
183
2
    int width = 500;
184
2
    int height = 350;
185
186

2
    getLayout().reflow(width, height);
187
2
    setContentSize(width, height);
188
189
2
    setMinWidth(310);
190
2
    setMinHeight(220);
191
6
    setDefaultSize(getWidth(), getHeight(), ImagePosition::CENTER, 0, 0);
192
193
2
    setResizable(true);
194
2
    addKeyListener(this);
195
196
2
    loadWindowState();
197
2
}
198
199
2
void ServerDialog::postInit()
200
{
201
2
    Window::postInit();
202
2
    setVisible(Visible_true);
203
204
2
    mConnectButton->requestFocus();
205
206
2
    loadServers(true);
207
208
2
    mServersList->setSelected(0);  // Do this after for the Delete button
209
210
2
    if (needUpdateServers())
211
1
        downloadServerList();
212
    else
213
1
        logger->log("Skipping servers list update");
214
2
}
215
216
14
ServerDialog::~ServerDialog()
217
{
218
2
    if (mDownload != nullptr)
219
    {
220
1
        mDownload->cancel();
221
1
        delete2(mDownload)
222
    }
223
4
    delete2(mServersListModel)
224
4
}
225
226
void ServerDialog::connectToSelectedServer()
227
{
228
    if (client->getState() == State::CONNECT_SERVER)
229
        return;
230
231
    const int index = mServersList->getSelected();
232
    if (index < 0)
233
        return;
234
235
    if (mDownload != nullptr)
236
        mDownload->cancel();
237
238
    mQuitButton->setEnabled(false);
239
    mConnectButton->setEnabled(false);
240
    mLoadButton->setEnabled(false);
241
242
    ServerInfo server = mServers.at(index);
243
    mServerInfo->hostname = server.hostname;
244
    mServerInfo->althostname = server.althostname;
245
    mServerInfo->port = server.port;
246
    mServerInfo->type = server.type;
247
    mServerInfo->name = server.name;
248
    mServerInfo->description = server.description;
249
    mServerInfo->registerUrl = server.registerUrl;
250
    mServerInfo->onlineListUrl = server.onlineListUrl;
251
    mServerInfo->supportUrl = server.supportUrl;
252
    mServerInfo->defaultHostName = server.defaultHostName;
253
    mServerInfo->save = true;
254
    mServerInfo->persistentIp = server.persistentIp;
255
    mServerInfo->freeType = server.freeType;
256
    mServerInfo->updateMirrors = server.updateMirrors;
257
    mServerInfo->packetVersion = server.packetVersion;
258
    mServerInfo->updateHosts = server.updateHosts;
259
    mServerInfo->freeSources = server.freeSources;
260
    mServerInfo->nonFreeSources = server.nonFreeSources;
261
    mServerInfo->docs = server.docs;
262
    mServerInfo->serverUrl = server.serverUrl;
263
264
    settings.persistentIp = mServerInfo->persistentIp;
265
    settings.supportUrl = mServerInfo->supportUrl;
266
    settings.updateMirrors = mServerInfo->updateMirrors;
267
268
    if (chatLogger != nullptr)
269
        chatLogger->setServerName(mServerInfo->hostname);
270
271
    saveCustomServers(*mServerInfo,
272
        -1);
273
274
    if (!LoginDialog::savedPasswordKey.empty())
275
    {
276
        if (mServerInfo->hostname != LoginDialog::savedPasswordKey)
277
        {
278
            LoginDialog::savedPassword.clear();
279
            if (desktop != nullptr)
280
                desktop->reloadWallpaper();
281
        }
282
    }
283
284
    config.setValue("usePersistentIP",
285
        mPersistentIPCheckBox->isSelected());
286
    client->setState(State::CONNECT_SERVER);
287
}
288
289
void ServerDialog::action(const ActionEvent &event)
290
{
291
    const std::string &eventId = event.getId();
292
    if (eventId == "connect")
293
    {
294
        connectToSelectedServer();
295
    }
296
    else if (eventId == "quit")
297
    {
298
        close();
299
    }
300
    else if (eventId == "load")
301
    {
302
        downloadServerList();
303
    }
304
    else if (eventId == "addEntry")
305
    {
306
        CREATEWIDGET(EditServerDialog, this, ServerInfo(), -1);
307
    }
308
    else if (eventId == "editEntry")
309
    {
310
        const int index = mServersList->getSelected();
311
        if (index >= 0)
312
        {
313
            CREATEWIDGET(EditServerDialog,
314
                this,
315
                mServers.at(index),
316
                index);
317
        }
318
    }
319
    else if (eventId == "remove")
320
    {
321
        const int index = mServersList->getSelected();
322
        if (index >= 0)
323
        {
324
            mServersList->setSelected(0);
325
            mServers.erase(mServers.begin() + index);
326
            saveCustomServers(ServerInfo(),
327
                -1);
328
        }
329
    }
330
    else if (eventId == "info")
331
    {
332
        const int index = mServersList->getSelected();
333
        if (index >= 0)
334
        {
335
            if (serverInfoWindow != nullptr)
336
                serverInfoWindow->scheduleDelete();
337
            serverInfoWindow = CREATEWIDGETR(ServerInfoWindow,
338
                mServers.at(index));
339
        }
340
    }
341
}
342
343
void ServerDialog::keyPressed(KeyEvent &event)
344
{
345
    PRAGMA45(GCC diagnostic push)
346
    PRAGMA45(GCC diagnostic ignored "-Wswitch-enum")
347
    switch (event.getActionId())
348
    {
349
        case InputAction::GUI_CANCEL:
350
            event.consume();
351
            client->setState(State::EXIT);
352
            return;
353
354
        case InputAction::GUI_SELECT:
355
        case InputAction::GUI_SELECT2:
356
            event.consume();
357
            action(ActionEvent(nullptr,
358
                mConnectButton->getActionEventId()));
359
            return;
360
361
        case InputAction::GUI_INSERT:
362
            CREATEWIDGET(EditServerDialog, this, ServerInfo(), -1);
363
            return;
364
365
        case InputAction::GUI_DELETE:
366
        {
367
            const int index = mServersList->getSelected();
368
            if (index >= 0)
369
            {
370
                mServersList->setSelected(0);
371
                mServers.erase(mServers.begin() + index);
372
                saveCustomServers(ServerInfo(),
373
                    -1);
374
            }
375
            return;
376
        }
377
378
        case InputAction::GUI_BACKSPACE:
379
        {
380
            const int index = mServersList->getSelected();
381
            if (index >= 0)
382
            {
383
                CREATEWIDGET(EditServerDialog, this, mServers.at(index),
384
                    index);
385
            }
386
            return;
387
        }
388
389
        default:
390
            break;
391
    }
392
    PRAGMA45(GCC diagnostic pop)
393
    if (!event.isConsumed())
394
        mServersList->keyPressed(event);
395
}
396
397
4
void ServerDialog::valueChanged(const SelectionEvent &event A_UNUSED)
398
{
399
8
    const int index = mServersList->getSelected();
400
4
    if (index == -1)
401
    {
402
        mDeleteButton->setEnabled(false);
403
        return;
404
    }
405
4
    mDeleteButton->setEnabled(true);
406
}
407
408
void ServerDialog::mouseClicked(MouseEvent &event)
409
{
410
    if (event.getButton() == MouseButton::LEFT)
411
    {
412
        event.consume();
413
        if (event.getClickCount() == 2 &&
414
            event.getSource() == mServersList)
415
        {
416
            action(ActionEvent(mConnectButton,
417
                mConnectButton->getActionEventId()));
418
        }
419
    }
420
}
421
422
void ServerDialog::logic()
423
{
424
    BLOCK_START("ServerDialog::logic")
425
    {
426
        MutexLocker tempLock(&mMutex);
427
        if (mDownloadStatus == ServerDialogDownloadStatus::COMPLETE)
428
        {
429
            loadServers(true);
430
            mDownloadStatus = ServerDialogDownloadStatus::OVER;
431
            mDescription->setCaption(std::string());
432
            logger->log("Servers list updated");
433
        }
434
        else if (mDownloadStatus == ServerDialogDownloadStatus::IN_PROGRESS)
435
        {
436
            // TRANSLATORS: servers dialog label
437
            mDescription->setCaption(strprintf(_("Downloading server list..."
438
                "%2.2f%%"), static_cast<double>(mDownloadProgress * 100)));
439
        }
440
        else if (mDownloadStatus == ServerDialogDownloadStatus::IDLE)
441
        {
442
            // TRANSLATORS: servers dialog label
443
            mDescription->setCaption(_("Waiting for server..."));
444
        }
445
        else if (mDownloadStatus == ServerDialogDownloadStatus::PREPARING)
446
        {
447
            // TRANSLATORS: servers dialog label
448
            mDescription->setCaption(_("Preparing download"));
449
        }
450
        else if (mDownloadStatus == ServerDialogDownloadStatus::ERROR)
451
        {
452
            // TRANSLATORS: servers dialog label
453
            mDescription->setCaption(_("Error retreiving server list!"));
454
            logger->log("Error: servers list updating error");
455
        }
456
    }
457
458
    Window::logic();
459
    BLOCK_END("ServerDialog::logic")
460
}
461
462
1
void ServerDialog::downloadServerList()
463
{
464
    // Try to load the configuration value for the onlineServerList
465
5
    std::string listFile = branding.getStringValue("onlineServerList");
466

5
    std::string listFile2 = branding.getStringValue("onlineServerList2");
467
468
    // Fall back to manaplus.org when neither branding
469
    // nor config set it
470
1
    if (listFile.empty())
471
        listFile = "http://manaplus.org/serverlist.xml";
472
473
1
    if (mDownload != nullptr)
474
    {
475
        mDownload->cancel();
476
        delete2(mDownload)
477
    }
478
479
1
    mDownload = new Net::Download(this, listFile,
480

1
        &downloadUpdate, false, false, true);
481
4
    mDownload->setFile(pathJoin(mDir,
482

5
        branding.getStringValue("onlineServerFile")),
483
1
        -1);
484
1
    if (!listFile2.empty())
485
1
        mDownload->addMirror(listFile2);
486
1
    mDownload->start();
487
488

5
    config.setValue("serverslistupdate", getDateString());
489
1
}
490
491
2
static void loadHostsGroup(XmlNodeConstPtr node,
492
                           ServerInfo &server)
493
{
494
4
    HostsGroup group;
495

10
    group.name = XML::langProperty(node,
496
        "name",
497
        // TRANSLATORS: unknown hosts group name
498
4
        _("Unknown"));
499
8
    for_each_xml_child_node(hostNode, node)
500
    {
501


14
        if (!xmlNameEqual(hostNode, "host") ||
502
4
            !XmlHaveChildContent(hostNode))
503
        {
504
4
            continue;
505
        }
506
8
        const std::string host = XmlChildContent(hostNode);
507
2
        if (host.empty())
508
            continue;
509

2
        if (!checkPath(host))
510
        {
511
            logger->log1("Warning: incorrect update server name");
512
            continue;
513
        }
514
515
2
        group.hosts.push_back(host);
516
    }
517
2
    if (!group.hosts.empty())
518
2
        server.updateHosts.push_back(group);
519
2
}
520
521
static void loadServerSourcesList(XmlNodeConstPtr node,
522
                                  STD_VECTOR<ServerUrlInfo> &list)
523
{
524
    for_each_xml_child_node(urlNode, node)
525
    {
526
        if (!xmlNameEqual(urlNode, "url") ||
527
            !XmlHaveChildContent(urlNode))
528
        {
529
            continue;
530
        }
531
        const std::string name = XML::langProperty(urlNode,
532
            "name",
533
            "");
534
        if (name.empty())
535
            continue;
536
        const std::string url = XmlChildContent(urlNode);
537
        if (url.empty())
538
            continue;
539
        list.push_back(ServerUrlInfo(name, url));
540
    }
541
}
542
543
static void loadServerSources(XmlNodeConstPtr node,
544
                              ServerInfo &server)
545
{
546
    for_each_xml_child_node(subNode, node)
547
    {
548
        if (xmlNameEqual(subNode, "free"))
549
        {
550
            loadServerSourcesList(subNode, server.freeSources);
551
        }
552
        else if (xmlNameEqual(subNode, "nonfree"))
553
        {
554
            loadServerSourcesList(subNode, server.nonFreeSources);
555
        }
556
    }
557
}
558
559
2
void ServerDialog::loadServers(const bool addNew)
560
{
561
8
    XML::Document doc(pathJoin(mDir,
562
8
        branding.getStringValue("onlineServerFile")),
563
        UseVirtFs_false,
564
6
        SkipError_true);
565
2
    XmlNodeConstPtr rootNode = doc.rootNode();
566
567

4
    if (rootNode == nullptr ||
568
2
        !xmlNameEqual(rootNode, "serverlist"))
569
    {
570
        logger->log1("Error loading server list!");
571
        return;
572
    }
573
574
2
    const int ver = XML::getProperty(rootNode, "version", 0);
575
2
    if (ver != 1)
576
    {
577
        logger->log("Error: unsupported online server list version: %d",
578
                    ver);
579
        return;
580
    }
581
582
4
    const std::string lang = getLangShort();
583
4
    const std::string description2("description_" + lang);
584
585
36
    for_each_xml_child_node(serverNode, rootNode)
586
    {
587

34
        if (!xmlNameEqual(serverNode, "server"))
588
20
            continue;
589
590
        const std::string type = XML::getProperty(
591

70
            serverNode, "type", "unknown");
592
28
        ServerInfo server;
593
14
        server.type = ServerInfo::parseType(type);
594
        const std::string licenseType = XML::getProperty(
595

70
            serverNode, "licenseType", "notset");
596
14
        server.freeType = ServerInfo::parseFreeType(licenseType);
597
598
        // Ignore unknown server types
599
14
        if (server.type == ServerType::UNKNOWN)
600
        {
601
            logger->log("Ignoring server entry with unknown type: %s",
602
                        type.c_str());
603
            continue;
604
        }
605
606
42
        server.name = XML::getProperty(serverNode, "name", std::string());
607
        std::string version = XML::getProperty(serverNode, "minimumVersion",
608
42
                                               std::string());
609
610

56
        const bool meetsMinimumVersion = (compareStrI(version, SMALL_VERSION)
611
14
                                   <= 0);
612
613
        // For display in the list
614
14
        if (meetsMinimumVersion)
615
            version.clear();
616
        else if (version.empty())
617
        {
618
            // TRANSLATORS: servers dialog label
619
            version = _("requires a newer version");
620
        }
621
        else
622
        {
623
            // TRANSLATORS: servers dialog label
624
            version = strprintf(_("requires v%s"), version.c_str());
625
        }
626
627
28
        const Font *const font = gui->getFont();
628
629
524
        for_each_xml_child_node(subNode, serverNode)
630
        {
631

510
            if (xmlNameEqual(subNode, "connection"))
632
            {
633

70
                server.hostname = XML::getProperty(subNode, "hostname", "");
634

70
                server.althostname = XML::getProperty(
635
14
                    subNode, "althostname", "");
636
14
                server.port = CAST_U16(
637
14
                    XML::getProperty(subNode, "port", 0));
638
14
                server.packetVersion = XML::getProperty(subNode,
639
                    "packetVersion", 0);
640
641
14
                if (server.port == 0)
642
                {
643
                    // If no port is given, use the default for the given type
644
                    server.port = defaultPortForServerType(server.type);
645
                }
646
            }
647

496
            else if (XmlHaveChildContent(subNode))
648
            {
649

464
                if ((xmlNameEqual(subNode, "description")
650

464
                    && server.description.empty()) || (!lang.empty()
651

218
                    && xmlNameEqual(subNode, description2.c_str())))
652
                {
653
26
                    server.description = XmlChildContent(subNode);
654
                }
655

206
                else if (xmlNameEqual(subNode, "registerurl"))
656
                {
657
2
                    server.registerUrl = XmlChildContent(subNode);
658
                }
659

204
                else if (xmlNameEqual(subNode, "onlineListUrl"))
660
                {
661
2
                    server.onlineListUrl = XmlChildContent(subNode);
662
                }
663

202
                else if (xmlNameEqual(subNode, "support"))
664
                {
665
10
                    server.supportUrl = XmlChildContent(subNode);
666
                }
667

192
                else if (xmlNameEqual(subNode, "persistentIp"))
668
                {
669
                    std::string text = XmlChildContent(subNode);
670
                    server.persistentIp = (text == "1" || text == "true");
671
                }
672

192
                else if (xmlNameEqual(subNode, "updateMirror"))
673
                {
674
40
                    server.updateMirrors.push_back(XmlChildContent(subNode));
675
                }
676

184
                else if (xmlNameEqual(subNode, "site"))
677
                {
678
14
                    server.serverUrl = XmlChildContent(subNode);
679
                }
680
            }
681

510
            if (xmlNameEqual(subNode, "updates"))
682
            {
683
2
                loadHostsGroup(subNode, server);
684
            }
685

508
            else if (xmlNameEqual(subNode, "defaultUpdateHost"))
686
            {
687

10
                server.defaultHostName = XML::langProperty(
688
                    // TRANSLATORS: default hosts group name
689
4
                    subNode, "name", _("default"));
690
            }
691

506
            else if (xmlNameEqual(subNode, "sources"))
692
            {
693
                loadServerSources(subNode, server);
694
            }
695

506
            else if (xmlNameEqual(subNode, "docs"))
696
            {
697
                loadServerSourcesList(subNode, server.docs);
698
            }
699
        }
700
701
14
        server.version.first = font->getWidth(version);
702
14
        server.version.second = version;
703
704
42
        MutexLocker tempLock(&mMutex);
705
        // Add the server to the local list if it's not already present
706
14
        bool found = false;
707
56
        for (unsigned int i = 0, fsz = CAST_U32(
708
28
             mServers.size()); i < fsz; i++)
709
        {
710
84
            if (mServers[i] == server)
711
            {
712
                // Use the name listed in the server list
713
                mServers[i].name = server.name;
714
                mServers[i].type = server.type;
715
                mServers[i].freeType = server.freeType;
716
                mServers[i].version = server.version;
717
                mServers[i].description = server.description;
718
                mServers[i].registerUrl = server.registerUrl;
719
                mServers[i].onlineListUrl = server.onlineListUrl;
720
                mServers[i].supportUrl = server.supportUrl;
721
                mServers[i].serverUrl = server.serverUrl;
722
                mServers[i].althostname = server.althostname;
723
                mServers[i].persistentIp = server.persistentIp;
724
                mServers[i].updateMirrors = server.updateMirrors;
725
                mServers[i].defaultHostName = server.defaultHostName;
726
                mServers[i].updateHosts = server.updateHosts;
727
                mServers[i].packetVersion = server.packetVersion;
728
                mServers[i].freeSources = server.freeSources;
729
                mServers[i].nonFreeSources = server.nonFreeSources;
730
                mServers[i].docs = server.docs;
731
                mServersListModel->setVersionString(i, version);
732
                found = true;
733
                break;
734
            }
735
        }
736
14
        if (!found && addNew)
737
14
            mServers.push_back(server);
738
    }
739
4
    if (mServersList->getSelected() < 0)
740
2
        mServersList->setSelected(0);
741
}
742
743
2
void ServerDialog::loadCustomServers()
744
{
745
32
    for (int i = 0; i < MAX_SERVERLIST; ++i)
746
    {
747
30
        const std::string index = toString(i);
748
30
        const std::string nameKey("MostUsedServerDescName" + index);
749
30
        const std::string descKey("MostUsedServerDescription" + index);
750
30
        const std::string hostKey("MostUsedServerName" + index);
751
30
        const std::string typeKey("MostUsedServerType" + index);
752
30
        const std::string portKey("MostUsedServerPort" + index);
753
        const std::string onlineListUrlKey
754
30
            ("MostUsedServerOnlineList" + index);
755
30
        const std::string persistentIpKey("persistentIp" + index);
756
        const std::string packetVersionKey
757
30
            ("MostUsedServerPacketVersion" + index);
758
759
30
        ServerInfo server;
760

150
        server.name = config.getValue(nameKey, "");
761

150
        server.description = config.getValue(descKey, "");
762

150
        server.onlineListUrl = config.getValue(onlineListUrlKey, "");
763

150
        server.hostname = config.getValue(hostKey, "");
764

150
        server.type = ServerInfo::parseType(config.getValue(typeKey, ""));
765
60
        server.persistentIp = config.getValue(
766
30
            persistentIpKey, 0) != 0 ? true : false;
767
30
        server.packetVersion = config.getValue(packetVersionKey, 0);
768
769
60
        const int defaultPort = defaultPortForServerType(server.type);
770
30
        server.port = CAST_U16(
771
30
            config.getValue(portKey, defaultPort));
772
773
        // skip invalid server
774
30
        if (!server.isValid())
775
30
            continue;
776
777
        server.save = true;
778
        mServers.push_back(server);
779
    }
780
2
}
781
782
void ServerDialog::saveCustomServers(const ServerInfo &currentServer,
783
                                     const int index)
784
{
785
    // Make sure the current server is mentioned first
786
    if (currentServer.isValid())
787
    {
788
        if (index >= 0 && CAST_SIZE(index) < mServers.size())
789
        {
790
            mServers[index] = currentServer;
791
        }
792
        else
793
        {
794
            FOR_EACH (ServerInfos::iterator, i, mServers)
795
            {
796
                if (*i == currentServer)
797
                {
798
                    mServers.erase(i);
799
                    break;
800
                }
801
            }
802
            mServers.insert(mServers.begin(), currentServer);
803
        }
804
    }
805
806
    int savedServerCount = 0;
807
808
    for (unsigned i = 0, fsz = CAST_U32(mServers.size());
809
         i < fsz && savedServerCount < MAX_SERVERLIST; ++ i)
810
    {
811
        const ServerInfo &server = mServers.at(i);
812
813
        // Only save servers that were loaded from settings
814
        if (!(server.save && server.isValid()))
815
            continue;
816
817
        const std::string num = toString(savedServerCount);
818
        const std::string nameKey("MostUsedServerDescName" + num);
819
        const std::string descKey("MostUsedServerDescription" + num);
820
        const std::string hostKey("MostUsedServerName" + num);
821
        const std::string typeKey("MostUsedServerType" + num);
822
        const std::string portKey("MostUsedServerPort" + num);
823
        const std::string onlineListUrlKey
824
            ("MostUsedServerOnlineList" + num);
825
        const std::string persistentIpKey("persistentIp" + num);
826
        const std::string packetVersionKey
827
            ("MostUsedServerPacketVersion" + num);
828
829
        config.setValue(nameKey, server.name);
830
        config.setValue(descKey, server.description);
831
        config.setValue(onlineListUrlKey, server.onlineListUrl);
832
        config.setValue(hostKey, server.hostname);
833
        config.setValue(typeKey, serverTypeToString(server.type));
834
        config.setValue(portKey, toString(server.port));
835
        config.setValue(persistentIpKey, server.persistentIp);
836
        config.setValue(packetVersionKey, server.packetVersion);
837
        ++ savedServerCount;
838
    }
839
840
    // Insert an invalid entry at the end to make the loading stop there
841
    if (savedServerCount < MAX_SERVERLIST)
842
        config.setValue("MostUsedServerName" + toString(savedServerCount), "");
843
}
844
845
int ServerDialog::downloadUpdate(void *ptr,
846
                                 const DownloadStatusT status,
847
                                 size_t total,
848
                                 const size_t remaining)
849
{
850
    if ((ptr == nullptr) || status == DownloadStatus::Cancelled)
851
        return -1;
852
853
    ServerDialog *const sd = reinterpret_cast<ServerDialog*>(ptr);
854
    bool finished = false;
855
856
    if (sd->mDownload == nullptr)
857
        return -1;
858
859
    if (status == DownloadStatus::Complete)
860
    {
861
        finished = true;
862
    }
863
    else if (CAST_S32(status) < 0)
864
    {
865
        logger->log("Error retreiving server list: %s\n",
866
                    sd->mDownload->getError());
867
        sd->mDownloadStatus = ServerDialogDownloadStatus::ERROR;
868
    }
869
    else
870
    {
871
        float progress = static_cast<float>(remaining);
872
        if (total != 0U)
873
            progress /= static_cast<float>(total);
874
875
        if (progress != progress || progress < 0.0F)
876
            progress = 0.0F;
877
        else if (progress > 1.0F)
878
            progress = 1.0F;
879
880
        MutexLocker lock1(&sd->mMutex);
881
        sd->mDownloadStatus = ServerDialogDownloadStatus::IN_PROGRESS;
882
        sd->mDownloadProgress = progress;
883
    }
884
885
    if (finished)
886
    {
887
        MutexLocker lock1(&sd->mMutex);
888
        sd->mDownloadStatus = ServerDialogDownloadStatus::COMPLETE;
889
    }
890
891
    return 0;
892
}
893
894
void ServerDialog::updateServer(const ServerInfo &server, const int index)
895
{
896
    saveCustomServers(server, index);
897
}
898
899
2
bool ServerDialog::needUpdateServers() const
900
{
901




16
    if (mServers.empty() || config.getStringValue("serverslistupdate")
902

8
        != getDateString())
903
    {
904
        return true;
905
    }
906
907
1
    return false;
908
}
909
910
void ServerDialog::close()
911
{
912
    if (mDownload != nullptr)
913
        mDownload->cancel();
914
    client->setState(State::FORCE_QUIT);
915
    Window::close();
916

3
}