GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/gui/windows/serverdialog.cpp Lines: 201 446 45.1 %
Date: 2017-11-29 Branches: 248 730 34.0 %

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

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

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

8
    mQuitButton(new Button(this, _("Quit"), "quit", this)),
109
    // TRANSLATORS: servers dialog button
110

8
    mConnectButton(new Button(this, _("Connect"), "connect", this)),
111
    // TRANSLATORS: servers dialog button
112

8
    mAddEntryButton(new Button(this, _("Add"), "addEntry", this)),
113
    // TRANSLATORS: servers dialog button
114

8
    mEditEntryButton(new Button(this, _("Edit"), "editEntry", this)),
115
    // TRANSLATORS: servers dialog button
116

8
    mDeleteButton(new Button(this, _("Delete"), "remove", this)),
117
    // TRANSLATORS: servers dialog button
118

8
    mLoadButton(new Button(this, _("Load"), "load", this)),
119
    // TRANSLATORS: servers dialog button
120

8
    mInfoButton(new Button(this, _("Info"), "info", this)),
121

4
    mServersListModel(new ServersListModel(&mServers, this)),
122

4
    mServersList(CREATEWIDGETR(ServersListBox, this, mServersListModel)),
123
    mDownload(nullptr),
124
    mServerInfo(serverInfo),
125
    mPersistentIPCheckBox(nullptr),
126
    mDownloadProgress(-1.0F),
127








260
    mDownloadStatus(ServerDialogDownloadStatus::UNKNOWN)
128
{
129
4
    if (isSafeMode)
130
    {
131
        // TRANSLATORS: servers dialog name
132
        setCaption(_("Choose Your Server  *** SAFE MODE ***"));
133
    }
134
135
20
    setWindowName("ServerDialog");
136
137
4
    setCloseButton(true);
138
139

28
    mPersistentIPCheckBox = new CheckBox(this,
140
        // TRANSLATORS: servers dialog checkbox
141
4
        _("Use same ip for game sub servers"),
142

16
        config.getBoolValue("usePersistentIP"),
143

4
        this, "persitent ip");
144
145
4
    loadCustomServers();
146
147
4
    mServersList->addMouseListener(this);
148
149
4
    ScrollArea *const usedScroll = new ScrollArea(this, mServersList,
150

16
        fromBool(getOptionBool("showbackground"), Opaque),
151

20
        "server_background.xml");
152
4
    usedScroll->setHorizontalScrollPolicy(ScrollArea::SHOW_NEVER);
153
154
4
    mServersList->addSelectionListener(this);
155
4
    usedScroll->setVerticalScrollAmount(0);
156
157
8
    place(0, 0, usedScroll, 8, 5).setPadding(3);
158
4
    place(0, 5, mDescription, 8);
159
4
    place(0, 6, mPersistentIPCheckBox, 8);
160
4
    place(0, 7, mInfoButton);
161
4
    place(1, 7, mAddEntryButton);
162
4
    place(2, 7, mEditEntryButton);
163
4
    place(3, 7, mLoadButton);
164
4
    place(4, 7, mDeleteButton);
165
4
    place(6, 7, mQuitButton);
166
4
    place(7, 7, mConnectButton);
167
168
    // Make sure the list has enough height
169

4
    getLayout().setRowHeight(0, 80);
170
171
    // Do this manually instead of calling reflowLayout so we can enforce a
172
    // minimum width.
173
4
    int width = 500;
174
4
    int height = 350;
175
176

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

5
    std::string listFile = branding.getStringValue("onlineServerList");
453

5
    std::string listFile2 = branding.getStringValue("onlineServerList2");
454
455
    // Fall back to manaplus.org when neither branding
456
    // nor config set it
457
1
    if (listFile.empty())
458
        listFile = "http://manaplus.org/serverlist.xml";
459
460
1
    if (mDownload != nullptr)
461
    {
462
        mDownload->cancel();
463
        delete2(mDownload)
464
    }
465
466
1
    mDownload = new Net::Download(this, listFile,
467

1
        &downloadUpdate, false, false, true);
468

4
    mDownload->setFile(pathJoin(mDir,
469

5
        branding.getStringValue("onlineServerFile")));
470
1
    if (!listFile2.empty())
471
1
        mDownload->addMirror(listFile2);
472
1
    mDownload->start();
473
474

5
    config.setValue("serverslistupdate", getDateString());
475
1
}
476
477
4
static void loadHostsGroup(XmlNodeConstPtr node,
478
                           ServerInfo &server)
479
{
480
8
    HostsGroup group;
481

20
    group.name = XML::langProperty(node,
482
        "name",
483
        // TRANSLATORS: unknown hosts group name
484
4
        _("Unknown"));
485
16
    for_each_xml_child_node(hostNode, node)
486
    {
487

24
        if (!xmlNameEqual(hostNode, "host") ||
488
8
            !XmlHaveChildContent(hostNode))
489
        {
490
16
            continue;
491
        }
492
16
        const std::string host = XmlChildContent(hostNode);
493
4
        if (host.empty())
494
            continue;
495

4
        if (!checkPath(host))
496
        {
497
            logger->log1("Warning: incorrect update server name");
498
            continue;
499
        }
500
501
4
        group.hosts.push_back(host);
502
    }
503
4
    if (!group.hosts.empty())
504
4
        server.updateHosts.push_back(group);
505
4
}
506
507
static void loadServerSourcesList(XmlNodeConstPtr node,
508
                                  STD_VECTOR<ServerUrlInfo> &list)
509
{
510
    for_each_xml_child_node(urlNode, node)
511
    {
512
        if (!xmlNameEqual(urlNode, "url") ||
513
            !XmlHaveChildContent(urlNode))
514
        {
515
            continue;
516
        }
517
        const std::string name = XML::langProperty(urlNode,
518
            "name",
519
            "");
520
        if (name.empty())
521
            continue;
522
        const std::string url = XmlChildContent(urlNode);
523
        if (url.empty())
524
            continue;
525
        list.push_back(ServerUrlInfo(name, url));
526
    }
527
}
528
529
static void loadServerSources(XmlNodeConstPtr node,
530
                              ServerInfo &server)
531
{
532
    for_each_xml_child_node(subNode, node)
533
    {
534
        if (xmlNameEqual(subNode, "free"))
535
        {
536
            loadServerSourcesList(subNode, server.freeSources);
537
        }
538
        else if (xmlNameEqual(subNode, "nonfree"))
539
        {
540
            loadServerSourcesList(subNode, server.nonFreeSources);
541
        }
542
    }
543
}
544
545
4
void ServerDialog::loadServers(const bool addNew)
546
{
547
16
    XML::Document doc(pathJoin(mDir,
548

20
        branding.getStringValue("onlineServerFile")),
549
        UseVirtFs_false,
550
8
        SkipError_true);
551
4
    XmlNodeConstPtr rootNode = doc.rootNode();
552
553

8
    if (rootNode == nullptr ||
554
4
        !xmlNameEqual(rootNode, "serverlist"))
555
    {
556
        logger->log1("Error loading server list!");
557
        return;
558
    }
559
560
4
    const int ver = XML::getProperty(rootNode, "version", 0);
561
4
    if (ver != 1)
562
    {
563
        logger->log("Error: unsupported online server list version: %d",
564
                    ver);
565
        return;
566
    }
567
568
8
    const std::string lang = getLangShort();
569
8
    const std::string description2("description_" + lang);
570
571
72
    for_each_xml_child_node(serverNode, rootNode)
572
    {
573

68
        if (!xmlNameEqual(serverNode, "server"))
574
80
            continue;
575
576
        const std::string type = XML::getProperty(
577

140
            serverNode, "type", "unknown");
578
56
        ServerInfo server;
579
28
        server.type = ServerInfo::parseType(type);
580
        const std::string licenseType = XML::getProperty(
581

140
            serverNode, "licenseType", "notset");
582
28
        server.freeType = ServerInfo::parseFreeType(licenseType);
583
584
        // Ignore unknown server types
585
28
        if (server.type == ServerType::UNKNOWN)
586
        {
587
            logger->log("Ignoring server entry with unknown type: %s",
588
                        type.c_str());
589
            continue;
590
        }
591
592
84
        server.name = XML::getProperty(serverNode, "name", std::string());
593
        std::string version = XML::getProperty(serverNode, "minimumVersion",
594
84
                                               std::string());
595
596

112
        const bool meetsMinimumVersion = (compareStrI(version, SMALL_VERSION)
597
28
                                   <= 0);
598
599
        // For display in the list
600
28
        if (meetsMinimumVersion)
601
            version.clear();
602
        else if (version.empty())
603
        {
604
            // TRANSLATORS: servers dialog label
605
            version = _("requires a newer version");
606
        }
607
        else
608
        {
609
            // TRANSLATORS: servers dialog label
610
            version = strprintf(_("requires v%s"), version.c_str());
611
        }
612
613
56
        const Font *const font = gui->getFont();
614
615
1048
        for_each_xml_child_node(subNode, serverNode)
616
        {
617

1020
            if (xmlNameEqual(subNode, "connection"))
618
            {
619

140
                server.hostname = XML::getProperty(subNode, "hostname", "");
620

140
                server.althostname = XML::getProperty(
621
                    subNode, "althostname", "");
622
28
                server.port = CAST_U16(
623
28
                    XML::getProperty(subNode, "port", 0));
624
28
                server.packetVersion = XML::getProperty(subNode,
625
                    "packetVersion", 0);
626
627
28
                if (server.port == 0)
628
                {
629
                    // If no port is given, use the default for the given type
630
                    server.port = defaultPortForServerType(server.type);
631
                }
632
            }
633

992
            else if (XmlHaveChildContent(subNode))
634
            {
635
464
                if ((xmlNameEqual(subNode, "description")
636

928
                    && server.description.empty()) || (!lang.empty()
637

436
                    && xmlNameEqual(subNode, description2.c_str())))
638
                {
639
52
                    server.description = XmlChildContent(subNode);
640
                }
641

412
                else if (xmlNameEqual(subNode, "registerurl"))
642
                {
643
4
                    server.registerUrl = XmlChildContent(subNode);
644
                }
645

408
                else if (xmlNameEqual(subNode, "onlineListUrl"))
646
                {
647
4
                    server.onlineListUrl = XmlChildContent(subNode);
648
                }
649

404
                else if (xmlNameEqual(subNode, "support"))
650
                {
651
20
                    server.supportUrl = XmlChildContent(subNode);
652
                }
653

384
                else if (xmlNameEqual(subNode, "persistentIp"))
654
                {
655
                    std::string text = XmlChildContent(subNode);
656
                    server.persistentIp = (text == "1" || text == "true");
657
                }
658

384
                else if (xmlNameEqual(subNode, "updateMirror"))
659
                {
660
80
                    server.updateMirrors.push_back(XmlChildContent(subNode));
661
                }
662

368
                else if (xmlNameEqual(subNode, "site"))
663
                {
664
28
                    server.serverUrl = XmlChildContent(subNode);
665
                }
666
            }
667

1020
            if (xmlNameEqual(subNode, "updates"))
668
            {
669
4
                loadHostsGroup(subNode, server);
670
            }
671

1016
            else if (xmlNameEqual(subNode, "defaultUpdateHost"))
672
            {
673

20
                server.defaultHostName = XML::langProperty(
674
                    // TRANSLATORS: default hosts group name
675
4
                    subNode, "name", _("default"));
676
            }
677

1012
            else if (xmlNameEqual(subNode, "sources"))
678
            {
679
                loadServerSources(subNode, server);
680
            }
681

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

300
        server.name = config.getValue(nameKey, "");
747

300
        server.description = config.getValue(descKey, "");
748

300
        server.onlineListUrl = config.getValue(onlineListUrlKey, "");
749

300
        server.hostname = config.getValue(hostKey, "");
750

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




32
    if (mServers.empty() || config.getStringValue("serverslistupdate")
888

16
        != getDateString())
889
    {
890
        return true;
891
    }
892
893
3
    return false;
894
}
895
896
void ServerDialog::close()
897
{
898
    if (mDownload != nullptr)
899
        mDownload->cancel();
900
    client->setState(State::FORCE_QUIT);
901
    Window::close();
902

6
}