GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/resources/db/groupdb.cpp Lines: 15 147 10.2 %
Date: 2018-07-14 Branches: 4 228 1.8 %

Line Branch Exec Source
1
/*
2
 *  The ManaPlus Client
3
 *  Copyright (C) 2016-2018  The ManaPlus Developers
4
 *
5
 *  This file is part of The ManaPlus Client.
6
 *
7
 *  This program is free software; you can redistribute it and/or modify
8
 *  it under the terms of the GNU General Public License as published by
9
 *  the Free Software Foundation; either version 2 of the License, or
10
 *  any later version.
11
 *
12
 *  This program is distributed in the hope that it will be useful,
13
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 *  GNU General Public License for more details.
16
 *
17
 *  You should have received a copy of the GNU General Public License
18
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
 */
20
21
#include "resources/db/groupdb.h"
22
23
#include "configuration.h"
24
25
#include "being/localplayer.h"
26
27
#include "utils/checkutils.h"
28
29
#ifdef TMWA_SUPPORT
30
#include "net/net.h"
31
#endif  // TMWA_SUPPORT
32
33
#include "resources/beingcommon.h"
34
#include "resources/groupinfo.h"
35
36
#include "debug.h"
37
38
namespace
39
{
40
1
    GroupDb::GroupInfos mGroups;
41
1
    const GroupInfo mEmptyGroup;
42
    bool mLoaded = false;
43
}  // namespace
44
45
void GroupDb::load()
46
{
47
    if (mLoaded)
48
        unload();
49
50
    logger->log1("Initializing group database...");
51
52
    loadXmlFile(paths.getStringValue("groupsFile"), SkipError_false);
53
    loadXmlFile(paths.getStringValue("groupsPatchFile"), SkipError_true);
54
    loadXmlDir("groupsPatchDir", loadXmlFile);
55
    mLoaded = true;
56
}
57
58
#define servercommandFirst(name) \
59
    if (str == #name) \
60
        return ServerCommandType::name; \
61
    else
62
#define servercommand(name) \
63
    if (str == #name) \
64
        return ServerCommandType::name; \
65
    else
66
#define servercommand2(name1, name2) \
67
    if (str == #name2) \
68
        return ServerCommandType::name1; \
69
    else
70
71
static ServerCommandTypeT parseCommand(const std::string &str,
72
                                       const int id)
73
{
74
#include "resources/servercommands.inc"
75
    {
76
        reportAlways("GroupsDb: unknown command name: '%s' in group id '%d'.",
77
            str.c_str(),
78
            id);
79
    }
80
81
    return ServerCommandType::Max;
82
}
83
84
SERVERCOMMANDS_VOID
85
#undef servercommandFirst
86
#undef servercommand
87
#undef servercommand2
88
89
#define serverpermissionFirst(name) \
90
    if (str == #name) \
91
        return ServerPermissionType::name; \
92
    else
93
#define serverpermission(name) \
94
    if (str == #name) \
95
        return ServerPermissionType::name; \
96
    else
97
98
static ServerPermissionTypeT parsePermission(const std::string &str,
99
                                             const int id)
100
{
101
#include "resources/serverpermissions.inc"
102
    {
103
        reportAlways("GroupsDb: unknown permission name: "
104
            "'%s' in group id '%d'.",
105
            str.c_str(),
106
            id);
107
    }
108
109
    return ServerPermissionType::Max;
110
}
111
112
SERVERPERMISSION_VOID
113
#undef serverpermissionFirst
114
#undef serverpermission
115
116
static ServerCommandEnable::Type parseUseFlag(const std::string &str,
117
                                              const int id)
118
{
119
    if (str == "self")
120
    {
121
        return ServerCommandEnable::Self;
122
    }
123
    else if (str == "other")
124
    {
125
        return ServerCommandEnable::Other;
126
    }
127
    else if (str == "both")
128
    {
129
        return ServerCommandEnable::Both;
130
    }
131
    else if (str == "false")
132
    {
133
        return ServerCommandEnable::No;
134
    }
135
    else
136
    {
137
        reportAlways("GroupsDb: unknown use flag: '%s' in group id '%d'."
138
            "Possible values 'self', 'other', 'both'.",
139
            str.c_str(),
140
            id);
141
        return ServerCommandEnable::No;
142
    }
143
}
144
145
static void loadCommands(XmlNodePtr rootNode,
146
                         const int id,
147
                         GroupInfo *groupInfo) A_NONNULL(3);
148
static void loadCommands(XmlNodePtr rootNode,
149
                         const int id,
150
                         GroupInfo *groupInfo)
151
{
152
    for_each_xml_child_node(node, rootNode)
153
    {
154
        if (xmlNameEqual(node, "command"))
155
        {
156
            const std::string nameStr = XML::getProperty(node,
157
                "name",
158
                "");
159
            const std::string useStr = XML::getProperty(node,
160
                "use",
161
                "");
162
            ServerCommandTypeT name = parseCommand(nameStr, id);
163
            if (name == ServerCommandType::Max)
164
                continue;
165
            ServerCommandEnable::Type useFlag = parseUseFlag(useStr, id);
166
            if (useFlag == ServerCommandEnable::No)
167
                continue;
168
            groupInfo->mCommands[CAST_SIZE(name)] = useFlag;
169
        }
170
    }
171
}
172
173
static void loadPermissions(XmlNodePtr rootNode,
174
                            const int id,
175
                            GroupInfo *groupInfo) A_NONNULL(3);
176
static void loadPermissions(XmlNodePtr rootNode,
177
                            const int id,
178
                            GroupInfo *groupInfo)
179
{
180
    for_each_xml_child_node(node, rootNode)
181
    {
182
        if (xmlNameEqual(node, "permission"))
183
        {
184
            const std::string nameStr = XML::getProperty(node,
185
                "name",
186
                "");
187
            ServerPermissionTypeT perm = parsePermission(nameStr, id);
188
            if (perm == ServerPermissionType::Max)
189
                continue;
190
            if (!XML::getBoolProperty(node,
191
                "enable",
192
                true))
193
            {
194
                continue;
195
            }
196
            groupInfo->mPermissions[CAST_SIZE(perm)] = Enable_true;
197
        }
198
    }
199
}
200
201
static void loadSubNodes(XmlNodePtr groupNode,
202
                         const int id,
203
                         GroupInfo *groupInfo) A_NONNULL(3);
204
static void loadSubNodes(XmlNodePtr groupNode,
205
                         const int id,
206
                         GroupInfo *groupInfo)
207
{
208
    for_each_xml_child_node(node, groupNode)
209
    {
210
        if (xmlNameEqual(node, "commands"))
211
            loadCommands(node, id, groupInfo);
212
        if (xmlNameEqual(node, "permissions"))
213
            loadPermissions(node, id, groupInfo);
214
    }
215
}
216
217
static void parseInherit(XmlNodePtr groupNode,
218
                         const int id,
219
                         GroupInfo *groupInfo) A_NONNULL(3);
220
static void parseInherit(XmlNodePtr groupNode,
221
                         const int id,
222
                         GroupInfo *groupInfo)
223
{
224
    const std::string inherit = XML::langProperty(groupNode,
225
        "inherit",
226
        "");
227
    STD_VECTOR<int> parts;
228
    splitToIntVector(parts, inherit, ',');
229
    FOR_EACH (STD_VECTOR<int>::const_iterator, it, parts)
230
    {
231
        const int id2 = *it;
232
        GroupDb::GroupInfos::const_iterator it2 = mGroups.find(id2);
233
        if (it2 == mGroups.end())
234
        {
235
            reportAlways("Unknown inherit group id '%d' in group '%d'",
236
                id2,
237
                id);
238
            continue;
239
        }
240
        GroupInfo *const groupInfo2 = (*it2).second;
241
        for (size_t f = 0; f < CAST_SIZE(ServerCommandType::Max); f ++)
242
        {
243
            ServerCommandEnable::Type enable = groupInfo2->mCommands[f];
244
            if (enable != ServerCommandEnable::No)
245
                groupInfo->mCommands[f] = enable;
246
        }
247
        for (size_t f = 0; f < CAST_SIZE(ServerPermissionType::Max); f ++)
248
        {
249
            if (groupInfo2->mPermissions[f] == Enable_true)
250
                groupInfo->mPermissions[f] = Enable_true;
251
        }
252
    }
253
}
254
255
void GroupDb::loadXmlFile(const std::string &fileName,
256
                          const SkipError skipError)
257
{
258
    XML::Document doc(fileName,
259
        UseVirtFs_true,
260
        skipError);
261
    XmlNodeConstPtrConst rootNode = doc.rootNode();
262
263
    if (rootNode == nullptr ||
264
        !xmlNameEqual(rootNode, "groups"))
265
    {
266
        if (skipError == SkipError_true)
267
        {
268
            logger->log("GroupsDb: Error while loading %s!",
269
                fileName.c_str());
270
        }
271
        else
272
        {
273
            reportAlways("GroupsDb: Error while loading %s!",
274
                fileName.c_str());
275
        }
276
        return;
277
    }
278
279
    for_each_xml_child_node(node, rootNode)
280
    {
281
        if (xmlNameEqual(node, "include"))
282
        {
283
            const std::string name = XML::getProperty(node, "name", "");
284
            if (!name.empty())
285
                loadXmlFile(name, skipError);
286
            continue;
287
        }
288
        if (xmlNameEqual(node, "group"))
289
        {
290
            const int id = XML::getProperty(node,
291
                "id",
292
                -1);
293
            if (id < 0)
294
            {
295
                reportAlways("Empty id field in GroupDb");
296
                continue;
297
            }
298
            GroupInfosIter it = mGroups.find(id);
299
            GroupInfo *group = nullptr;
300
            if (it != mGroups.end())
301
            {
302
                reportAlways("GroupDb: group with id %d already added",
303
                    id);
304
                group = (*it).second;
305
            }
306
            else
307
            {
308
                group = new GroupInfo;
309
                mGroups[id] = group;
310
            }
311
            group->name = XML::langProperty(node,
312
                "name",
313
                "");
314
            group->longName = XML::langProperty(node,
315
                "longName",
316
                "");
317
            group->badge = XML::langProperty(node,
318
                "badge",
319
                paths.getStringValue("gmbadge"));
320
            group->showBadge = XML::getBoolProperty(node,
321
                "showBadge",
322
                false);
323
            group->highlightName = XML::getBoolProperty(node,
324
                "highlightName",
325
                false);
326
            loadSubNodes(node, id, group);
327
            parseInherit(node, id, group);
328
        }
329
    }
330
}
331
332
214
void GroupDb::unload()
333
{
334
214
    logger->log1("Unloading group database...");
335
428
    FOR_EACH (GroupInfosIter, it, mGroups)
336
    {
337
        delete (*it).second;
338
    }
339
214
    mGroups.clear();
340
214
    mLoaded = false;
341
214
}
342
343
1
const std::string &GroupDb::getName(const int id)
344
{
345
2
    GroupInfos::const_iterator it = mGroups.find(id);
346
1
    if (it == mGroups.end())
347
    {
348
        reportAlways("Unknown group id requested: %d", id);
349
        return mEmptyGroup.name;
350
    }
351
1
    return (*it).second->name;
352
}
353
354
const std::string &GroupDb::getLongName(const int id)
355
{
356
    GroupInfos::const_iterator it = mGroups.find(id);
357
    if (it == mGroups.end())
358
    {
359
        reportAlways("Unknown group id requested: %d", id);
360
        return mEmptyGroup.longName;
361
    }
362
    return (*it).second->longName;
363
}
364
365
bool GroupDb::getShowBadge(const int id)
366
{
367
    GroupInfos::const_iterator it = mGroups.find(id);
368
    if (it == mGroups.end())
369
    {
370
        reportAlways("Unknown group id requested: %d", id);
371
        return mEmptyGroup.showBadge;
372
    }
373
    return (*it).second->showBadge;
374
}
375
376
bool GroupDb::getHighlightName(const int id)
377
{
378
    GroupInfos::const_iterator it = mGroups.find(id);
379
    if (it == mGroups.end())
380
    {
381
        reportAlways("Unknown group id requested: %d", id);
382
        return mEmptyGroup.highlightName;
383
    }
384
    return (*it).second->highlightName;
385
}
386
387
const std::string &GroupDb::getBadge(const int id)
388
{
389
    GroupInfos::const_iterator it = mGroups.find(id);
390
    if (it == mGroups.end())
391
    {
392
        reportAlways("Unknown group id requested: %d", id);
393
        return mEmptyGroup.badge;
394
    }
395
    return (*it).second->badge;
396
}
397
398
const GroupInfo *GroupDb::getGroup(const int id)
399
{
400
    GroupInfos::const_iterator it = mGroups.find(id);
401
    if (it == mGroups.end())
402
    {
403
        reportAlways("Unknown group id requested: %d", id);
404
        return &mEmptyGroup;
405
    }
406
    return (*it).second;
407
}
408
409
bool GroupDb::isAllowCommand(const ServerCommandTypeT command)
410
{
411
    const int groupId = localPlayer->getGroupId();
412
    const GroupInfo *const group = GroupDb::getGroup(groupId);
413
414
#ifdef TMWA_SUPPORT
415
    // allow any commands for legacy if group > 0
416
    if (Net::getNetworkType() == ServerType::TMWATHENA &&
417
        localPlayer != nullptr &&
418
        localPlayer->isGM())
419
    {
420
        return true;
421
    }
422
#endif
423
    if (group->mPermissions[CAST_SIZE(ServerPermissionType::all_commands)] ==
424
        Enable_true)
425
    {
426
        return true;
427
    }
428
    const ServerCommandEnable::Type enabled =
429
        group->mCommands[CAST_SIZE(command)];
430
    return (enabled & ServerCommandEnable::Self) != 0;
431
}
432
433
#ifdef UNITTESTS
434
1
GroupDb::GroupInfos &GroupDb::getGroups()
435
{
436
1
    return mGroups;
437

3
}
438
#endif  // UNITTESTS