GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/configmanager.cpp Lines: 58 210 27.6 %
Date: 2021-03-17 Branches: 54 542 10.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-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 "configmanager.h"
25
26
#include "client.h"
27
#include "configuration.h"
28
#include "settings.h"
29
30
#include "being/beingspeech.h"
31
32
#include "fs/files.h"
33
#include "fs/mkdir.h"
34
#include "fs/paths.h"
35
36
#include "utils/cast.h"
37
#include "utils/checkutils.h"
38
#include "utils/gettext.h"
39
40
#include "render/renderers.h"
41
42
#include "debug.h"
43
44
154
static void setDefaultOption(const char *const name,
45
                             const bool def)
46
{
47
616
    const int val = serverConfig.getValue(name, -1);
48
154
    if (val == -1)
49
770
        serverConfig.setValue(name, def);
50
154
}
51
52
/**
53
 * Initializes the home directory. On UNIX and FreeBSD, ~/.mana is used. On
54
 * Windows and other systems we use the current working directory.
55
 */
56
77
void ConfigManager::initServerConfig(const std::string &serverName)
57
{
58
231
    settings.serverConfigDir = pathJoin(settings.configDir, serverName);
59
60
77
    if (mkdir_r(settings.serverConfigDir.c_str()) != 0)
61
    {
62
        // TRANSLATORS: directory creation error
63
        logger->error(strprintf(_("%s doesn't exist and can't be created! "
64
            "Exiting."), settings.serverConfigDir.c_str()));
65
    }
66
154
    const std::string configPath = settings.serverConfigDir + "/config.xml";
67
77
    FILE *configFile = fopen(configPath.c_str(), "r");
68
77
    if (configFile == nullptr)
69
    {
70
77
        configFile = fopen(configPath.c_str(), "wb");
71

154
        logger->log("Creating new server config: " + configPath);
72
77
        if (configFile != nullptr)
73
        {
74
77
            fputs("<?xml version=\"1.0\"?>\n", configFile);
75
77
            fputs("<configuration>\n", configFile);
76
77
            fputs("</configuration>\n", configFile);
77
        }
78
    }
79
77
    if (configFile != nullptr)
80
    {
81
77
        fclose(configFile);
82
        serverConfig.init(configPath,
83
            UseVirtFs_false,
84
77
            SkipError_false);
85
77
        setConfigDefaults(serverConfig);
86

154
        logger->log("serverConfigPath: " + configPath);
87
    }
88
    else
89
    {
90
        reportAlways("Error creating server config: %s",
91
            configPath.c_str())
92
    }
93
94
154
    const bool val = Client::isTmw();
95
77
    setDefaultOption("enableManaMarketBot", val);
96
77
    setDefaultOption("enableRemoteCommands", !val);
97
77
}
98
99
302
void ConfigManager::initConfiguration()
100
{
101
#ifdef DEBUG_CONFIG
102
    config.setIsMain(true);
103
#endif  // DEBUG_CONFIG
104
105
    // Fill configuration with defaults
106
1510
    config.setValue("hwaccel", false);
107
#ifdef USE_OPENGL
108
#if (defined __APPLE__)
109
    config.setValue("opengl", CAST_S32(RENDER_NORMAL_OPENGL));
110
#elif (defined ANDROID)
111
    config.setValue("opengl", CAST_S32(RENDER_GLES_OPENGL));
112
#elif (defined WIN32)
113
    config.setValue("opengl", CAST_S32(RENDER_SAFE_OPENGL));
114
#else  // (defined __APPLE__)
115
116
1208
    config.setValue("opengl", CAST_S32(RENDER_SOFTWARE));
117
#endif  // (defined __APPLE__)
118
#else  // USE_OPENGL
119
120
    config.setValue("opengl", CAST_S32(RENDER_SOFTWARE));
121
#endif  // USE_OPENGL
122
123
1510
    config.setValue("screen", false);
124
1510
    config.setValue("sound", true);
125
1208
    config.setValue("guialpha", 0.8F);
126
//    config.setValue("remember", true);
127
1208
    config.setValue("sfxVolume", 100);
128
1208
    config.setValue("musicVolume", 60);
129
1208
    config.setValue("fpslimit", 60);
130

2416
    std::string defaultUpdateHost = branding.getValue("defaultUpdateHost", "");
131

302
    if (!checkPath(defaultUpdateHost))
132
        defaultUpdateHost.clear();
133

1208
    config.setValue("updatehost", defaultUpdateHost);
134
1510
    config.setValue("useScreenshotDirectorySuffix", true);
135

1208
    config.setValue("ChatLogLength", 128);
136
137
604
    std::string configPath;
138
139
#ifndef UNITTESTS
140
    if (settings.options.test.empty())
141
        configPath = settings.configDir + "/config.xml";
142
    else
143
        configPath = settings.configDir + "/test.xml";
144
#else  // UNITTESTS
145
146
604
    configPath = settings.configDir + "/unittestconfig.xml";
147
#endif  // UNITTESTS
148
149
302
    FILE *configFile = fopen(configPath.c_str(), "r");
150
302
    if (configFile == nullptr)
151
    {
152
1
        configFile = fopen(configPath.c_str(), "wb");
153
1
        logger->log1("Creating new config");
154
1
        if (configFile != nullptr)
155
        {
156
1
            fputs("<?xml version=\"1.0\"?>\n", configFile);
157
1
            fputs("<configuration>\n", configFile);
158
1
            fputs("</configuration>\n", configFile);
159
        }
160
    }
161
302
    if (configFile == nullptr)
162
    {
163
        reportAlways("Can't create %s. Using defaults.",
164
            configPath.c_str())
165
    }
166
    else
167
    {
168
302
        fclose(configFile);
169
        config.init(configPath,
170
            UseVirtFs_false,
171
302
            SkipError_false);
172
302
        logger->log1("init 3");
173
302
        setConfigDefaults(config);
174
302
        setConfigDefaults(serverConfig);
175

604
        logger->log("configuration file: " + configPath);
176
    }
177
302
}
178
179
void ConfigManager::backupConfig(const std::string &name)
180
{
181
    const std::string fileName3 = pathJoin(settings.configDir, name);
182
    StringVect arr;
183
    if (Files::existsLocal(fileName3) == false)
184
    {
185
        logger->log("Config %s not exists, backup skipped.",
186
            name.c_str());
187
        return;
188
    }
189
    if (Files::loadTextFileLocal(fileName3, arr) == true)
190
    {
191
        if (arr.empty())
192
            return;
193
194
        arr.clear();
195
        const std::string tmpName = pathJoin(settings.configDir,
196
            name).append(".tmp");
197
        Files::copyFile(fileName3, tmpName);
198
        if (Files::loadTextFileLocal(tmpName, arr) == false ||
199
            arr.empty())
200
        {
201
            logger->safeError("Error backuping configs. "
202
                "Probably no free space on disk.");
203
        }
204
        arr.clear();
205
    }
206
207
    const std::string confName = pathJoin(settings.configDir,
208
        name).append(".bak");
209
    const int maxFileIndex = 5;
210
    ::remove((confName + toString(maxFileIndex)).c_str());
211
    for (int f = maxFileIndex; f > 1; f --)
212
    {
213
        const std::string fileName1 = confName + toString(f - 1);
214
        const std::string fileName2 = confName + toString(f);
215
        Files::renameFile(fileName1, fileName2);
216
    }
217
    const std::string fileName4 = confName + toString(1);
218
    Files::copyFile(fileName3, fileName4);
219
}
220
221
#ifdef __native_client__
222
void ConfigManager::storeSafeParameters()
223
{
224
    RenderType tmpOpengl;
225
226
    isSafeMode = config.getBoolValue("safemode");
227
    if (isSafeMode)
228
        logger->log1("Run in safe mode");
229
230
    tmpOpengl = intToRenderType(config.getIntValue("opengl"));
231
232
    config.setValue("opengl", CAST_S32(RENDER_SOFTWARE));
233
234
    config.write();
235
236
    if (settings.options.safeMode)
237
    {
238
        isSafeMode = true;
239
        return;
240
    }
241
242
    config.setValue("safemode", false);
243
    config.setValue("opengl", CAST_S32(tmpOpengl));
244
}
245
#elif !defined(ANDROID)
246
void ConfigManager::storeSafeParameters()
247
{
248
    bool tmpHwaccel;
249
    RenderType tmpOpengl;
250
    int tmpFpslimit;
251
    int tmpAltFpslimit;
252
    bool tmpSound;
253
    int width;
254
    int height;
255
    std::string font;
256
    std::string bFont;
257
    std::string particleFont;
258
    std::string helpFont;
259
    std::string secureFont;
260
    std::string npcFont;
261
    std::string japanFont;
262
    std::string chinaFont;
263
    bool showBackground;
264
    bool enableMumble;
265
    bool enableMapReduce;
266
267
    isSafeMode = config.getBoolValue("safemode");
268
    if (isSafeMode)
269
        logger->log1("Run in safe mode");
270
271
    tmpOpengl = intToRenderType(config.getIntValue("opengl"));
272
273
    width = config.getIntValue("screenwidth");
274
    height = config.getIntValue("screenheight");
275
    tmpHwaccel = config.getBoolValue("hwaccel");
276
277
    tmpFpslimit = config.getIntValue("fpslimit");
278
    tmpAltFpslimit = config.getIntValue("altfpslimit");
279
    tmpSound = config.getBoolValue("sound");
280
281
    font = config.getStringValue("font");
282
    bFont = config.getStringValue("boldFont");
283
    particleFont = config.getStringValue("particleFont");
284
    helpFont = config.getStringValue("helpFont");
285
    secureFont = config.getStringValue("secureFont");
286
    npcFont = config.getStringValue("npcFont");
287
    japanFont = config.getStringValue("japanFont");
288
    chinaFont = config.getStringValue("chinaFont");
289
290
    showBackground = config.getBoolValue("showBackground");
291
    enableMumble = config.getBoolValue("enableMumble");
292
    enableMapReduce = config.getBoolValue("enableMapReduce");
293
294
    if (!settings.options.safeMode && tmpOpengl == RENDER_SOFTWARE)
295
    {
296
        // if video mode configured reset most settings to safe
297
        config.setValue("hwaccel", false);
298
        config.setValue("altfpslimit", 3);
299
        config.setValue("sound", false);
300
        config.setValue("safemode", true);
301
        config.setValue("screenwidth", 640);
302
        config.setValue("screenheight", 480);
303
        config.setValue("font", "fonts/dejavusans.ttf");
304
        config.setValue("boldFont", "fonts/dejavusans-bold.ttf");
305
        config.setValue("particleFont", "fonts/dejavusans.ttf");
306
        config.setValue("helpFont", "fonts/dejavusansmono.ttf");
307
        config.setValue("secureFont", "fonts/dejavusansmono.ttf");
308
        config.setValue("npcFont", "fonts/dejavusans.ttf");
309
        config.setValue("japanFont", "fonts/mplus-1p-regular.ttf");
310
        config.setValue("chinaFont", "fonts/wqy-microhei.ttf");
311
        config.setValue("showBackground", false);
312
        config.setValue("enableMumble", false);
313
        config.setValue("enableMapReduce", false);
314
    }
315
    else
316
    {
317
        // if video mode not configured reset only video mode to safe
318
        config.setValue("screenwidth", 640);
319
        config.setValue("screenheight", 480);
320
    }
321
#if defined(__APPLE__)
322
    config.setValue("opengl", CAST_S32(RENDER_NORMAL_OPENGL));
323
#else  // defined(__APPLE__)
324
325
    config.setValue("opengl", CAST_S32(RENDER_SOFTWARE));
326
#endif  // defined(__APPLE__)
327
328
    config.write();
329
330
    if (settings.options.safeMode)
331
    {
332
        isSafeMode = true;
333
        return;
334
    }
335
336
    config.setValue("safemode", false);
337
    if (tmpOpengl == RENDER_SOFTWARE)
338
    {
339
        config.setValue("hwaccel", tmpHwaccel);
340
        config.setValue("opengl", CAST_S32(tmpOpengl));
341
        config.setValue("fpslimit", tmpFpslimit);
342
        config.setValue("altfpslimit", tmpAltFpslimit);
343
        config.setValue("sound", tmpSound);
344
        config.setValue("screenwidth", width);
345
        config.setValue("screenheight", height);
346
        config.setValue("font", font);
347
        config.setValue("boldFont", bFont);
348
        config.setValue("particleFont", particleFont);
349
        config.setValue("helpFont", helpFont);
350
        config.setValue("secureFont", secureFont);
351
        config.setValue("npcFont", npcFont);
352
        config.setValue("japanFont", japanFont);
353
        config.setValue("chinaFont", chinaFont);
354
        config.setValue("showBackground", showBackground);
355
        config.setValue("enableMumble", enableMumble);
356
        config.setValue("enableMapReduce", enableMapReduce);
357
    }
358
    else
359
    {
360
        config.setValue("opengl", CAST_S32(tmpOpengl));
361
        config.setValue("screenwidth", width);
362
        config.setValue("screenheight", height);
363
    }
364
}
365
#endif  // __native_client__
366
367
#define unassignKey(key, value) \
368
    if (config.getStringValue(prefix + (key)) == (value)) \
369
        config.setValue(key, "-1");
370
371
void ConfigManager::checkConfigVersion()
372
{
373
    const int version = config.getIntValue("cfgver");
374
    if (version < 1)
375
    {
376
        if (config.getIntValue("fontSize") == 11)
377
            config.deleteKey("fontSize");
378
        if (config.getIntValue("npcfontSize") == 13)
379
            config.deleteKey("npcfontSize");
380
    }
381
    if (version < 2)
382
    {
383
        if (config.getIntValue("screenButtonsSize") == 1)
384
            config.deleteKey("screenButtonsSize");
385
        if (config.getIntValue("screenJoystickSize") == 1)
386
            config.deleteKey("screenJoystickSize");
387
    }
388
    if (version < 3)
389
    {
390
        config.setValue("audioFrequency", 44100);
391
#ifdef ANDROID
392
        config.setValue("customcursor", false);
393
#endif  // ANDROID
394
    }
395
#ifdef ANDROID
396
    if (version < 4)
397
    {
398
        config.setValue("showDidYouKnow", false);
399
    }
400
#endif  // ANDROID
401
402
    if (version < 5)
403
    {
404
        if (config.getIntValue("speech") == BeingSpeech::TEXT_OVERHEAD)
405
        {
406
            config.setValue("speech", CAST_S32(
407
                BeingSpeech::NO_NAME_IN_BUBBLE));
408
        }
409
    }
410
    if (version < 6)
411
        config.setValue("blur", false);
412
413
    if (version < 7)
414
        config.setValue("download-music", true);
415
416
    if (version < 9)
417
    {
418
        config.deleteKey("videodetected");
419
        config.setValue("moveToTargetType", 10);
420
    }
421
    if (version < 10)
422
        config.setValue("enableLazyScrolling", false);
423
424
    if (version < 11)
425
    {
426
#ifdef USE_SDL2
427
        const std::string prefix = std::string("sdl2");
428
#else  // USE_SDL2
429
430
        const std::string prefix = std::string();
431
#endif  // USE_SDL2
432
433
        unassignKey("keyDirectUp", "k108")
434
        unassignKey("keyDirectDown", "k59")
435
        unassignKey("keyDirectLeft", "k107")
436
        unassignKey("keyDirectRight", "k39")
437
    }
438
    if (version < 12)
439
    {
440
#ifdef USE_SDL2
441
        const std::string prefix = std::string("sdl2");
442
#else  // USE_SDL2
443
444
        const std::string prefix = std::string();
445
#endif  // USE_SDL2
446
447
        unassignKey("keyAttack", "k120")
448
    }
449
450
    if (version < 13)
451
        config.setValue("keyWindowBotChecker", -1);
452
453
    if (version < 14 && config.getIntValue("syncPlayerMoveDistance") == 2)
454
        config.setValue("syncPlayerMoveDistance", 5);
455
    config.setValue("cfgver", 14);
456
}
457
458
#undef unassignKey