GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/resources/db/groupdb.cpp Lines: 15 134 11.2 %
Date: 2017-11-29 Branches: 4 222 1.8 %

Line Branch Exec Source
1
/*
2
 *  The ManaPlus Client
3
 *  Copyright (C) 2016-2017  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 "utils/checkutils.h"
26
27
#include "resources/beingcommon.h"
28
#include "resources/groupinfo.h"
29
30
#include "debug.h"
31
32
namespace
33
{
34
2
    GroupDb::GroupInfos mGroups;
35
2
    const GroupInfo mEmptyGroup;
36
    bool mLoaded = false;
37
}  // namespace
38
39
void GroupDb::load()
40
{
41
    if (mLoaded)
42
        unload();
43
44
    logger->log1("Initializing group database...");
45
46
    loadXmlFile(paths.getStringValue("groupsFile"), SkipError_false);
47
    loadXmlFile(paths.getStringValue("groupsPatchFile"), SkipError_true);
48
    loadXmlDir("groupsPatchDir", loadXmlFile);
49
    mLoaded = true;
50
}
51
52
#define servercommandFirst(name) \
53
    if (str == #name) \
54
        return ServerCommandType::name; \
55
    else
56
#define servercommand(name) \
57
    if (str == #name) \
58
        return ServerCommandType::name; \
59
    else
60
#define servercommand2(name1, name2) \
61
    if (str == #name2) \
62
        return ServerCommandType::name1; \
63
    else
64
65
static ServerCommandTypeT parseCommand(const std::string &str,
66
                                       const int id)
67
{
68
#include "resources/servercommands.inc"
69
    {
70
        reportAlways("GroupsDb: unknown command name: '%s' in group id '%d'.",
71
            str.c_str(),
72
            id);
73
    }
74
75
    return ServerCommandType::Max;
76
}
77
78
SERVERCOMMANDS_VOID
79
#undef servercommandFirst
80
#undef servercommand
81
#undef servercommand2
82
83
#define serverpermissionFirst(name) \
84
    if (str == #name) \
85
        return ServerPermissionType::name; \
86
    else
87
#define serverpermission(name) \
88
    if (str == #name) \
89
        return ServerPermissionType::name; \
90
    else
91
92
static ServerPermissionTypeT parsePermission(const std::string &str,
93
                                             const int id)
94
{
95
#include "resources/serverpermissions.inc"
96
    {
97
        reportAlways("GroupsDb: unknown permission name: "
98
            "'%s' in group id '%d'.",
99
            str.c_str(),
100
            id);
101
    }
102
103
    return ServerPermissionType::Max;
104
}
105
106
SERVERPERMISSION_VOID
107
#undef serverpermissionFirst
108
#undef serverpermission
109
110
static ServerCommandEnable::Type parseUseFlag(const std::string &str,
111
                                              const int id)
112
{
113
    if (str == "self")
114
    {
115
        return ServerCommandEnable::Self;
116
    }
117
    else if (str == "other")
118
    {
119
        return ServerCommandEnable::Other;
120
    }
121
    else if (str == "both")
122
    {
123
        return ServerCommandEnable::Both;
124
    }
125
    else if (str == "false")
126
    {
127
        return ServerCommandEnable::No;
128
    }
129
    else
130
    {
131
        reportAlways("GroupsDb: unknown use flag: '%s' in group id '%d'."
132
            "Possible values 'self', 'other', 'both'.",
133
            str.c_str(),
134
            id);
135
        return ServerCommandEnable::No;
136
    }
137
}
138
139
static void loadCommands(XmlNodePtr rootNode,
140
                         const int id,
141
                         GroupInfo *groupInfo) A_NONNULL(3);
142
static void loadCommands(XmlNodePtr rootNode,
143
                         const int id,
144
                         GroupInfo *groupInfo)
145
{
146
    for_each_xml_child_node(node, rootNode)
147
    {
148
        if (xmlNameEqual(node, "command"))
149
        {
150
            const std::string nameStr = XML::getProperty(node,
151
                "name",
152
                "");
153
            const std::string useStr = XML::getProperty(node,
154
                "use",
155
                "");
156
            ServerCommandTypeT name = parseCommand(nameStr, id);
157
            if (name == ServerCommandType::Max)
158
                continue;
159
            ServerCommandEnable::Type useFlag = parseUseFlag(useStr, id);
160
            if (useFlag == ServerCommandEnable::No)
161
                continue;
162
            groupInfo->mCommands[CAST_SIZE(name)] = useFlag;
163
        }
164
    }
165
}
166
167
static void loadPermissions(XmlNodePtr rootNode,
168
                            const int id,
169
                            GroupInfo *groupInfo) A_NONNULL(3);
170
static void loadPermissions(XmlNodePtr rootNode,
171
                            const int id,
172
                            GroupInfo *groupInfo)
173
{
174
    for_each_xml_child_node(node, rootNode)
175
    {
176
        if (xmlNameEqual(node, "permission"))
177
        {
178
            const std::string nameStr = XML::getProperty(node,
179
                "name",
180
                "");
181
            ServerPermissionTypeT perm = parsePermission(nameStr, id);
182
            if (perm == ServerPermissionType::Max)
183
                continue;
184
            if (!XML::getBoolProperty(node,
185
                "enable",
186
                true))
187
            {
188
                continue;
189
            }
190
            groupInfo->mPermissions[CAST_SIZE(perm)] = Enable_true;
191
        }
192
    }
193
}
194
195
static void loadSubNodes(XmlNodePtr groupNode,
196
                         const int id,
197
                         GroupInfo *groupInfo) A_NONNULL(3);
198
static void loadSubNodes(XmlNodePtr groupNode,
199
                         const int id,
200
                         GroupInfo *groupInfo)
201
{
202
    for_each_xml_child_node(node, groupNode)
203
    {
204
        if (xmlNameEqual(node, "commands"))
205
            loadCommands(node, id, groupInfo);
206
        if (xmlNameEqual(node, "permissions"))
207
            loadPermissions(node, id, groupInfo);
208
    }
209
}
210
211
static void parseInherit(XmlNodePtr groupNode,
212
                         const int id,
213
                         GroupInfo *groupInfo) A_NONNULL(3);
214
static void parseInherit(XmlNodePtr groupNode,
215
                         const int id,
216
                         GroupInfo *groupInfo)
217
{
218
    const std::string inherit = XML::langProperty(groupNode,
219
        "inherit",
220
        "");
221
    STD_VECTOR<int> parts;
222
    splitToIntVector(parts, inherit, ',');
223
    FOR_EACH (STD_VECTOR<int>::const_iterator, it, parts)
224
    {
225
        const int id2 = *it;
226
        GroupDb::GroupInfos::const_iterator it2 = mGroups.find(id2);
227
        if (it2 == mGroups.end())
228
        {
229
            reportAlways("Unknown inherit group id '%d' in group '%d'",
230
                id2,
231
                id);
232
            continue;
233
        }
234
        GroupInfo *const groupInfo2 = (*it2).second;
235
        for (size_t f = 0; f < CAST_SIZE(ServerCommandType::Max); f ++)
236
        {
237
            ServerCommandEnable::Type enable = groupInfo2->mCommands[f];
238
            if (enable != ServerCommandEnable::No)
239
                groupInfo->mCommands[f] = enable;
240
        }
241
        for (size_t f = 0; f < CAST_SIZE(ServerPermissionType::Max); f ++)
242
        {
243
            if (groupInfo2->mPermissions[f] == Enable_true)
244
                groupInfo->mPermissions[f] = Enable_true;
245
        }
246
    }
247
}
248
249
void GroupDb::loadXmlFile(const std::string &fileName,
250
                          const SkipError skipError)
251
{
252
    XML::Document doc(fileName,
253
        UseVirtFs_true,
254
        skipError);
255
    XmlNodeConstPtrConst rootNode = doc.rootNode();
256
257
    if (rootNode == nullptr ||
258
        !xmlNameEqual(rootNode, "groups"))
259
    {
260
        if (skipError == SkipError_true)
261
        {
262
            logger->log("GroupsDb: Error while loading %s!",
263
                fileName.c_str());
264
        }
265
        else
266
        {
267
            reportAlways("GroupsDb: Error while loading %s!",
268
                fileName.c_str());
269
        }
270
        return;
271
    }
272
273
    for_each_xml_child_node(node, rootNode)
274
    {
275
        if (xmlNameEqual(node, "include"))
276
        {
277
            const std::string name = XML::getProperty(node, "name", "");
278
            if (!name.empty())
279
                loadXmlFile(name, skipError);
280
            continue;
281
        }
282
        if (xmlNameEqual(node, "group"))
283
        {
284
            const int id = XML::getProperty(node,
285
                "id",
286
                -1);
287
            if (id < 0)
288
            {
289
                reportAlways("Empty id field in GroupDb");
290
                continue;
291
            }
292
            GroupInfosIter it = mGroups.find(id);
293
            GroupInfo *group = nullptr;
294
            if (it != mGroups.end())
295
            {
296
                reportAlways("GroupDb: group with id %d already added",
297
                    id);
298
                group = (*it).second;
299
            }
300
            else
301
            {
302
                group = new GroupInfo;
303
                mGroups[id] = group;
304
            }
305
            group->name = XML::langProperty(node,
306
                "name",
307
                "");
308
            group->longName = XML::langProperty(node,
309
                "longName",
310
                "");
311
            group->badge = XML::langProperty(node,
312
                "badge",
313
                paths.getStringValue("gmbadge"));
314
            group->showBadge = XML::getBoolProperty(node,
315
                "showBadge",
316
                false);
317
            loadSubNodes(node, id, group);
318
            parseInherit(node, id, group);
319
        }
320
    }
321
}
322
323
384
void GroupDb::unload()
324
{
325
384
    logger->log1("Unloading group database...");
326
768
    FOR_EACH (GroupInfosIter, it, mGroups)
327
    {
328
        delete (*it).second;
329
    }
330
384
    mGroups.clear();
331
384
    mLoaded = false;
332
384
}
333
334
2
const std::string &GroupDb::getName(const int id)
335
{
336
4
    GroupInfos::const_iterator it = mGroups.find(id);
337
2
    if (it == mGroups.end())
338
    {
339
        reportAlways("Unknown group id requested: %d", id);
340
        return mEmptyGroup.name;
341
    }
342
2
    return (*it).second->name;
343
}
344
345
const std::string &GroupDb::getLongName(const int id)
346
{
347
    GroupInfos::const_iterator it = mGroups.find(id);
348
    if (it == mGroups.end())
349
    {
350
        reportAlways("Unknown group id requested: %d", id);
351
        return mEmptyGroup.longName;
352
    }
353
    return (*it).second->longName;
354
}
355
356
bool GroupDb::getShowBadge(const int id)
357
{
358
    GroupInfos::const_iterator it = mGroups.find(id);
359
    if (it == mGroups.end())
360
    {
361
        reportAlways("Unknown group id requested: %d", id);
362
        return mEmptyGroup.showBadge;
363
    }
364
    return (*it).second->showBadge;
365
}
366
367
const std::string &GroupDb::getBadge(const int id)
368
{
369
    GroupInfos::const_iterator it = mGroups.find(id);
370
    if (it == mGroups.end())
371
    {
372
        reportAlways("Unknown group id requested: %d", id);
373
        return mEmptyGroup.badge;
374
    }
375
    return (*it).second->badge;
376
}
377
378
const GroupInfo *GroupDb::getGroup(const int id)
379
{
380
    GroupInfos::const_iterator it = mGroups.find(id);
381
    if (it == mGroups.end())
382
    {
383
        reportAlways("Unknown group id requested: %d", id);
384
        return &mEmptyGroup;
385
    }
386
    return (*it).second;
387
}
388
389
#ifdef UNITTESTS
390
2
GroupDb::GroupInfos &GroupDb::getGroups()
391
{
392
2
    return mGroups;
393

6
}
394
#endif  // UNITTESTS