1 /* ====================================================================
2 * The Kannel Software License, Version 1.0
3 *
4 * Copyright (c) 2001-2014 Kannel Group
5 * Copyright (c) 1998-2001 WapIT Ltd.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in
17 * the documentation and/or other materials provided with the
18 * distribution.
19 *
20 * 3. The end-user documentation included with the redistribution,
21 * if any, must include the following acknowledgment:
22 * "This product includes software developed by the
23 * Kannel Group (http://www.kannel.org/)."
24 * Alternately, this acknowledgment may appear in the software itself,
25 * if and wherever such third-party acknowledgments normally appear.
26 *
27 * 4. The names "Kannel" and "Kannel Group" must not be used to
28 * endorse or promote products derived from this software without
29 * prior written permission. For written permission, please
30 * contact org@kannel.org.
31 *
32 * 5. Products derived from this software may not be called "Kannel",
33 * nor may "Kannel" appear in their name, without prior written
34 * permission of the Kannel Group.
35 *
36 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39 * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
40 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
41 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
42 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
43 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
44 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
45 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
46 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47 * ====================================================================
48 *
49 * This software consists of voluntary contributions made by many
50 * individuals on behalf of the Kannel Group. For more information on
51 * the Kannel Group, please see <http://www.kannel.org/>.
52 *
53 * Portions of this software are based upon software originally written at
54 * WapIT Ltd., Helsinki, Finland for the Kannel project.
55 */
56
57 /*
58 * cfg.c - configuration file handling
59 *
60 * Lars Wirzenius
61 */
62
63
64 #include "gwlib/gwlib.h"
65
66 /* for include dir */
67 #include <sys/types.h>
68 #include <sys/stat.h>
69 #include <unistd.h>
70 #include <dirent.h>
71 #include <errno.h>
72
73 struct CfgGroup {
74 Octstr *name;
75 Dict *vars;
76 Octstr *configfile;
77 long line;
78 };
79
80
create_group(void)81 static CfgGroup *create_group(void)
82 {
83 CfgGroup *grp;
84
85 grp = gw_malloc(sizeof(*grp));
86 grp->name = NULL;
87 grp->vars = dict_create(64, octstr_destroy_item);
88 grp->configfile = NULL;
89 grp->line = 0;
90 return grp;
91 }
92
destroy_group(void * arg)93 static void destroy_group(void *arg)
94 {
95 CfgGroup *grp;
96
97 if (arg != NULL) {
98 grp = arg;
99 octstr_destroy(grp->name);
100 octstr_destroy(grp->configfile);
101 dict_destroy(grp->vars);
102 gw_free(grp);
103 }
104 }
105
106
107 struct CfgLoc {
108 Octstr *filename;
109 long line_no;
110 Octstr *line;
111 };
112
113
cfgloc_create(Octstr * filename)114 static CfgLoc *cfgloc_create(Octstr *filename)
115 {
116 CfgLoc *cfgloc;
117
118 cfgloc = gw_malloc(sizeof(*cfgloc));
119 cfgloc->filename = octstr_duplicate(filename);
120 cfgloc->line_no = 0;
121 cfgloc->line = NULL;
122 return cfgloc;
123 }
124
125
cfgloc_destroy(CfgLoc * cfgloc)126 static void cfgloc_destroy(CfgLoc *cfgloc)
127 {
128 if (cfgloc != NULL) {
129 octstr_destroy(cfgloc->filename);
130 octstr_destroy(cfgloc->line);
131 gw_free(cfgloc);
132 }
133 }
134
135
destroy_group_list(void * arg)136 static void destroy_group_list(void *arg)
137 {
138 gwlist_destroy(arg, destroy_group);
139 }
140
141
set_group_name(CfgGroup * grp,Octstr * name)142 static void set_group_name(CfgGroup *grp, Octstr *name)
143 {
144 octstr_destroy(grp->name);
145 grp->name = octstr_duplicate(name);
146 }
147
148
149 struct Cfg {
150 Octstr *filename;
151 Dict *single_groups;
152 Dict *multi_groups;
153 };
154
155
156 /********************************************************************
157 * Section providing hooks to external modules to apply their specific
158 * is_allowed_in_group() and is_single_group() with their own
159 * foobar-cfg.def.
160 */
161
162 static List *allowed_hooks;
163 static List *single_hooks;
164
core_is_allowed_in_group(Octstr * group,Octstr * variable)165 static int core_is_allowed_in_group(Octstr *group, Octstr *variable)
166 {
167 Octstr *groupstr;
168
169 groupstr = octstr_imm("group");
170
171 #define OCTSTR(name) \
172 if (octstr_compare(octstr_imm(#name), variable) == 0) \
173 return 1;
174 #define SINGLE_GROUP(name, fields) \
175 if (octstr_compare(octstr_imm(#name), group) == 0) { \
176 if (octstr_compare(groupstr, variable) == 0) \
177 return 1; \
178 fields \
179 return 0; \
180 }
181 #define MULTI_GROUP(name, fields) \
182 if (octstr_compare(octstr_imm(#name), group) == 0) { \
183 if (octstr_compare(groupstr, variable) == 0) \
184 return 1; \
185 fields \
186 return 0; \
187 }
188 #include "cfg.def"
189
190 /* unknown group identifier */
191 return -1;
192 }
193
194
core_is_single_group(Octstr * query)195 static int core_is_single_group(Octstr *query)
196 {
197 #define OCTSTR(name)
198 #define SINGLE_GROUP(name, fields) \
199 if (octstr_compare(octstr_imm(#name), query) == 0) \
200 return 1;
201 #define MULTI_GROUP(name, fields) \
202 if (octstr_compare(octstr_imm(#name), query) == 0) \
203 return 0;
204 #include "cfg.def"
205 return 0;
206 }
207
208
is_allowed_in_group(Octstr * group,Octstr * variable)209 static int is_allowed_in_group(Octstr *group, Octstr *variable)
210 {
211 long i;
212 int x, r = -1;
213
214 for (i = 0; i < gwlist_len(allowed_hooks); ++i) {
215 x = ((int(*)(Octstr *, Octstr *))
216 gwlist_get(allowed_hooks, i))(group, variable);
217 r = (x == -1 ? (r == -1 ? x : r) : (r == -1 ? x : r + x));
218 }
219
220 return r;
221 }
222
223
is_single_group(Octstr * query)224 static int is_single_group(Octstr *query)
225 {
226 long i;
227 int r = 0;
228
229 for (i = 0; i < gwlist_len(single_hooks); ++i) {
230 r += ((int(*)(Octstr *))
231 gwlist_get(single_hooks, i))(query);
232 }
233
234 return (r > 0);
235 }
236
237
cfg_add_hooks(void * allowed,void * single)238 void cfg_add_hooks(void *allowed, void *single)
239 {
240 gwlist_append(allowed_hooks, allowed);
241 gwlist_append(single_hooks, single);
242 }
243
244
add_group(Cfg * cfg,CfgGroup * grp)245 static int add_group(Cfg *cfg, CfgGroup *grp)
246 {
247 Octstr *groupname;
248 Octstr *name;
249 List *names;
250 List *list;
251
252 groupname = cfg_get(grp, octstr_imm("group"));
253 if (groupname == NULL) {
254 error(0, "Group does not contain variable 'group'.");
255 return -1;
256 }
257 set_group_name(grp, groupname);
258
259 names = dict_keys(grp->vars);
260
261 while ((name = gwlist_extract_first(names)) != NULL) {
262 int a = is_allowed_in_group(groupname, name);
263 switch (a) {
264 case 0:
265 error(0, "Group '%s' may not contain field '%s'.",
266 octstr_get_cstr(groupname), octstr_get_cstr(name));
267 octstr_destroy(name);
268 octstr_destroy(groupname);
269 gwlist_destroy(names, octstr_destroy_item);
270 return -1;
271 break;
272 case -1:
273 error(0, "Group '%s' is no valid group identifier.",
274 octstr_get_cstr(groupname));
275 octstr_destroy(name);
276 octstr_destroy(groupname);
277 gwlist_destroy(names, octstr_destroy_item);
278 return -1;
279 break;
280 default:
281 octstr_destroy(name);
282 break;
283 }
284 }
285 gwlist_destroy(names, NULL);
286
287 if (is_single_group(groupname)) {
288 dict_put(cfg->single_groups, groupname, grp);
289 } else {
290 list = dict_get(cfg->multi_groups, groupname);
291 if (list == NULL) {
292 list = gwlist_create();
293 dict_put(cfg->multi_groups, groupname, list);
294 }
295 gwlist_append(list, grp);
296 }
297
298 octstr_destroy(groupname);
299 return 0;
300 }
301
302
cfg_create(Octstr * filename)303 Cfg *cfg_create(Octstr *filename)
304 {
305 Cfg *cfg;
306
307 cfg = gw_malloc(sizeof(*cfg));
308 cfg->filename = octstr_duplicate(filename);
309 cfg->single_groups = dict_create(64, destroy_group);
310 cfg->multi_groups = dict_create(64, destroy_group_list);
311
312 return cfg;
313 }
314
315
cfg_destroy(Cfg * cfg)316 void cfg_destroy(Cfg *cfg)
317 {
318 if (cfg != NULL) {
319 octstr_destroy(cfg->filename);
320 dict_destroy(cfg->single_groups);
321 dict_destroy(cfg->multi_groups);
322 gw_free(cfg);
323 }
324 }
325
326
parse_value(Octstr * value)327 static void parse_value(Octstr *value)
328 {
329 Octstr *temp;
330 long len;
331 int c;
332
333 octstr_strip_blanks(value);
334
335 len = octstr_len(value);
336 if (octstr_get_char(value, 0) != '"' ||
337 octstr_get_char(value, len - 1) != '"')
338 return;
339
340 octstr_delete(value, len - 1, 1);
341 octstr_delete(value, 0, 1);
342
343 temp = octstr_duplicate(value);
344 octstr_truncate(value, 0);
345
346 while (octstr_len(temp) > 0) {
347 c = octstr_get_char(temp, 0);
348 octstr_delete(temp, 0, 1);
349
350 if (c != '\\' || octstr_len(temp) == 0)
351 octstr_append_char(value, c);
352 else {
353 c = octstr_get_char(temp, 0);
354 octstr_delete(temp, 0, 1);
355
356 switch (c) {
357 case '\\':
358 case '"':
359 octstr_append_char(value, c);
360 break;
361
362 default:
363 octstr_append_char(value, '\\');
364 octstr_append_char(value, c);
365 break;
366 }
367 }
368 }
369
370 octstr_destroy(temp);
371 }
372
373
expand_file(Octstr * file,int forward)374 static List *expand_file(Octstr *file, int forward)
375 {
376 Octstr *os;
377 Octstr *line;
378 List *lines;
379 List *expand;
380 long lineno;
381 CfgLoc *loc = NULL;
382
383 os = octstr_read_file(octstr_get_cstr(file));
384 if (os == NULL)
385 return NULL;
386
387 lines = octstr_split(os, octstr_imm("\n"));
388 lineno = 0;
389 expand = gwlist_create();
390
391 while ((line = gwlist_extract_first(lines)) != NULL) {
392 if (loc == NULL) {
393 ++lineno;
394 loc = cfgloc_create(file);
395 loc->line_no = lineno;
396 loc->line = octstr_create("");
397 if (forward)
398 gwlist_append(expand, loc);
399 else
400 gwlist_insert(expand, 0, loc);
401 }
402 /* check for escape and then add to existing loc */
403 if (octstr_get_char(line, octstr_len(line) - 1) == '\\') {
404 octstr_delete(line, octstr_len(line) - 1, 1);
405 octstr_append(loc->line, line);
406 /* check for second escape */
407 if (octstr_get_char(line, octstr_len(line) - 1) == '\\')
408 loc = NULL;
409 } else {
410 octstr_append(loc->line, line);
411 loc = NULL;
412 }
413 octstr_destroy(line);
414 }
415
416 /*
417 * add newline at each end of included files to avoid
418 * concatenating different groups by mistake
419 */
420 if (lineno > 0) {
421 loc = cfgloc_create(file);
422 loc->line_no = lineno;
423 loc->line = octstr_create("\n");
424 if (forward)
425 gwlist_append(expand, loc);
426 else
427 gwlist_insert(expand, 0, loc);
428 }
429
430 gwlist_destroy(lines, octstr_destroy_item);
431 octstr_destroy(os);
432
433 return expand;
434 }
435
436
cfg_read(Cfg * cfg)437 int cfg_read(Cfg *cfg)
438 {
439 CfgLoc *loc;
440 CfgLoc *loc_inc;
441 List *lines;
442 List *expand;
443 List *stack;
444 Octstr *name;
445 Octstr *value;
446 Octstr *filename;
447 CfgGroup *grp;
448 long equals;
449 long error_lineno;
450
451 loc = loc_inc = NULL;
452
453 /*
454 * expand initial main config file and add it to the recursion
455 * stack to protect against cycling
456 */
457 if ((lines = expand_file(cfg->filename, 1)) == NULL) {
458 panic(0, "Failed to load main configuration file `%s'. Aborting!",
459 octstr_get_cstr(cfg->filename));
460 }
461 stack = gwlist_create();
462 gwlist_insert(stack, 0, octstr_duplicate(cfg->filename));
463
464 grp = NULL;
465 error_lineno = 0;
466 while (error_lineno == 0 && (loc = gwlist_extract_first(lines)) != NULL) {
467 octstr_strip_blanks(loc->line);
468 if (octstr_len(loc->line) == 0) {
469 if (grp != NULL && add_group(cfg, grp) == -1) {
470 error_lineno = loc->line_no;
471 destroy_group(grp);
472 }
473 grp = NULL;
474 } else if (octstr_get_char(loc->line, 0) != '#') {
475 equals = octstr_search_char(loc->line, '=', 0);
476 if (equals == -1) {
477 error(0, "An equals sign ('=') is missing on line %ld of file %s.",
478 loc->line_no, octstr_get_cstr(loc->filename));
479 error_lineno = loc->line_no;
480 } else
481
482 /*
483 * check for special config directives, like include or conditional
484 * directives here
485 */
486 if (octstr_search(loc->line, octstr_imm("include"), 0) != -1) {
487 filename = octstr_copy(loc->line, equals + 1, octstr_len(loc->line));
488 parse_value(filename);
489
490 /* check if we are cycling */
491 if (gwlist_search(stack, filename, octstr_item_match) != NULL) {
492 panic(0, "Recursive include for config file `%s' detected "
493 "(on line %ld of file %s).",
494 octstr_get_cstr(filename), loc->line_no,
495 octstr_get_cstr(loc->filename));
496 } else {
497 List *files = gwlist_create();
498 Octstr *file;
499 struct stat filestat;
500
501 /* check if included file is a directory */
502 if (lstat(octstr_get_cstr(filename), &filestat) != 0) {
503 error(errno, "lstat failed: couldn't stat `%s'",
504 octstr_get_cstr(filename));
505 panic(0, "Failed to include `%s' "
506 "(on line %ld of file %s). Aborting!",
507 octstr_get_cstr(filename), loc->line_no,
508 octstr_get_cstr(loc->filename));
509 }
510
511 /*
512 * is a directory, create a list with files of
513 * this directory and load all as part of the
514 * whole configuration.
515 */
516 if (S_ISDIR(filestat.st_mode)) {
517 DIR *dh;
518 struct dirent *diritem;
519
520 debug("gwlib.cfg", 0, "Loading include dir `%s' "
521 "(on line %ld of file %s).",
522 octstr_get_cstr(filename), loc->line_no,
523 octstr_get_cstr(loc->filename));
524
525 dh = opendir(octstr_get_cstr(filename));
526 while ((diritem = readdir(dh))) {
527 Octstr *fileitem;
528
529 fileitem = octstr_duplicate(filename);
530 octstr_append_cstr(fileitem, "/");
531 octstr_append_cstr(fileitem, diritem->d_name);
532
533 lstat(octstr_get_cstr(fileitem), &filestat);
534 if (!S_ISDIR(filestat.st_mode)) {
535 gwlist_insert(files, 0, fileitem);
536 } else {
537 octstr_destroy(fileitem);
538 }
539 }
540 closedir(dh);
541 }
542
543 /* is a file, create a list with it */
544 else {
545 gwlist_insert(files, 0, octstr_duplicate(filename));
546 }
547
548 /* include files */
549 while ((file = gwlist_extract_first(files)) != NULL) {
550
551 gwlist_insert(stack, 0, octstr_duplicate(file));
552 debug("gwlib.cfg", 0, "Loading include file `%s' (on line %ld of file %s).",
553 octstr_get_cstr(file), loc->line_no,
554 octstr_get_cstr(loc->filename));
555
556 /*
557 * expand the given include file and add it to the current
558 * processed main while loop
559 */
560 if ((expand = expand_file(file, 0)) != NULL) {
561 while ((loc_inc = gwlist_extract_first(expand)) != NULL)
562 gwlist_insert(lines, 0, loc_inc);
563 } else {
564 panic(0, "Failed to load whole configuration. Aborting!");
565 }
566
567 gwlist_destroy(expand, NULL);
568 cfgloc_destroy(loc_inc);
569 octstr_destroy(file);
570 }
571 gwlist_destroy(files, octstr_destroy_item);
572 }
573 octstr_destroy(filename);
574 }
575
576 /*
577 * this is a "normal" line, so process it accodingly
578 */
579 else {
580 name = octstr_copy(loc->line, 0, equals);
581 octstr_strip_blanks(name);
582 value = octstr_copy(loc->line, equals + 1, octstr_len(loc->line));
583 parse_value(value);
584
585 if (grp == NULL)
586 grp = create_group();
587
588 if (grp->configfile != NULL) {
589 octstr_destroy(grp->configfile);
590 grp->configfile = NULL;
591 }
592 grp->configfile = octstr_duplicate(cfg->filename);
593
594 cfg_set(grp, name, value);
595 octstr_destroy(name);
596 octstr_destroy(value);
597 }
598 }
599
600 cfgloc_destroy(loc);
601 }
602
603 if (grp != NULL && add_group(cfg, grp) == -1) {
604 error_lineno = 1;
605 destroy_group(grp);
606 }
607
608 gwlist_destroy(lines, NULL);
609 gwlist_destroy(stack, octstr_destroy_item);
610
611 if (error_lineno != 0) {
612 error(0, "Error found on line %ld of file `%s'.",
613 error_lineno, octstr_get_cstr(cfg->filename));
614 return -1;
615 }
616
617 return 0;
618 }
619
620
cfg_get_single_group(Cfg * cfg,Octstr * name)621 CfgGroup *cfg_get_single_group(Cfg *cfg, Octstr *name)
622 {
623 return dict_get(cfg->single_groups, name);
624 }
625
626
cfg_get_multi_group(Cfg * cfg,Octstr * name)627 List *cfg_get_multi_group(Cfg *cfg, Octstr *name)
628 {
629 List *list, *copy;
630 long i;
631
632 list = dict_get(cfg->multi_groups, name);
633 if (list == NULL)
634 return NULL;
635
636 copy = gwlist_create();
637 for (i = 0; i < gwlist_len(list); ++i)
638 gwlist_append(copy, gwlist_get(list, i));
639 return copy;
640 }
641
642
cfg_get_group_name(CfgGroup * grp)643 Octstr *cfg_get_group_name(CfgGroup *grp)
644 {
645 return octstr_duplicate(grp->name);
646 }
647
cfg_get_configfile(CfgGroup * grp)648 Octstr *cfg_get_configfile(CfgGroup *grp)
649 {
650 return octstr_duplicate(grp->configfile);
651 }
652
653
cfg_get_real(CfgGroup * grp,Octstr * varname,const char * file,long line,const char * func)654 Octstr *cfg_get_real(CfgGroup *grp, Octstr *varname, const char *file,
655 long line, const char *func)
656 {
657 Octstr *os;
658
659 if(grp == NULL)
660 panic(0, "Trying to fetch variable `%s' in non-existing group",
661 octstr_get_cstr(varname));
662
663 if (grp->name != NULL && !is_allowed_in_group(grp->name, varname))
664 panic(0, "Trying to fetch variable `%s' in group `%s', not allowed.",
665 octstr_get_cstr(varname), octstr_get_cstr(grp->name));
666
667 os = dict_get(grp->vars, varname);
668 if (os == NULL)
669 return NULL;
670 return gw_claim_area_for(octstr_duplicate(os), file, line, func);
671 }
672
673
cfg_get_integer(long * n,CfgGroup * grp,Octstr * varname)674 int cfg_get_integer(long *n, CfgGroup *grp, Octstr *varname)
675 {
676 Octstr *os;
677 int ret;
678
679 os = cfg_get(grp, varname);
680 if (os == NULL)
681 return -1;
682 if (octstr_parse_long(n, os, 0, 0) == -1)
683 ret = -1;
684 else
685 ret = 0;
686 octstr_destroy(os);
687 return ret;
688 }
689
690
cfg_get_bool(int * n,CfgGroup * grp,Octstr * varname)691 int cfg_get_bool(int *n, CfgGroup *grp, Octstr *varname)
692 {
693 Octstr *os;
694
695 os = cfg_get(grp, varname);
696 if (os == NULL) {
697 *n = 0;
698 return -1;
699 }
700 if (octstr_case_compare(os, octstr_imm("true")) == 0
701 || octstr_case_compare(os, octstr_imm("yes")) == 0
702 || octstr_case_compare(os, octstr_imm("on")) == 0
703 || octstr_case_compare(os, octstr_imm("1")) == 0)
704 {
705 *n = 1;
706 } else if (octstr_case_compare(os, octstr_imm("false")) == 0
707 || octstr_case_compare(os, octstr_imm("no")) == 0
708 || octstr_case_compare(os, octstr_imm("off")) == 0
709 || octstr_case_compare(os, octstr_imm("0")) == 0)
710 {
711 *n = 0;
712 }
713 else {
714 *n = 1;
715 warning(0, "bool variable set to strange value, assuming 'true'");
716 }
717 octstr_destroy(os);
718 return 0;
719 }
720
721
cfg_get_list(CfgGroup * grp,Octstr * varname)722 List *cfg_get_list(CfgGroup *grp, Octstr *varname)
723 {
724 Octstr *os;
725 List *list;
726
727 os = cfg_get(grp, varname);
728 if (os == NULL)
729 return NULL;
730
731 list = octstr_split_words(os);
732 octstr_destroy(os);
733 return list;
734 }
735
736
cfg_set(CfgGroup * grp,Octstr * varname,Octstr * value)737 void cfg_set(CfgGroup *grp, Octstr *varname, Octstr *value)
738 {
739 dict_put(grp->vars, varname, octstr_duplicate(value));
740 }
741
742
grp_dump(CfgGroup * grp)743 void grp_dump(CfgGroup *grp)
744 {
745 List *names;
746 Octstr *name;
747 Octstr *value;
748
749 if (grp->name == NULL)
750 debug("gwlib.cfg", 0, " dumping group (name not set):");
751 else
752 debug("gwlib.cfg", 0, " dumping group (%s):",
753 octstr_get_cstr(grp->name));
754 names = dict_keys(grp->vars);
755 while ((name = gwlist_extract_first(names)) != NULL) {
756 value = cfg_get(grp, name);
757 debug("gwlib.cfg", 0, " <%s> = <%s>",
758 octstr_get_cstr(name),
759 octstr_get_cstr(value));
760 octstr_destroy(value);
761 octstr_destroy(name);
762 }
763 gwlist_destroy(names, NULL);
764 }
765
766
cfg_dump(Cfg * cfg)767 void cfg_dump(Cfg *cfg)
768 {
769 CfgGroup *grp;
770 List *list;
771 List *names;
772 Octstr *name;
773
774 debug("gwlib.cfg", 0, "Dumping Cfg %p", (void *) cfg);
775 debug("gwlib.cfg", 0, " filename = <%s>",
776 octstr_get_cstr(cfg->filename));
777
778 names = dict_keys(cfg->single_groups);
779 while ((name = gwlist_extract_first(names)) != NULL) {
780 grp = cfg_get_single_group(cfg, name);
781 if (grp != NULL)
782 grp_dump(grp);
783 octstr_destroy(name);
784 }
785 gwlist_destroy(names, NULL);
786
787 names = dict_keys(cfg->multi_groups);
788 while ((name = gwlist_extract_first(names)) != NULL) {
789 list = cfg_get_multi_group(cfg, name);
790 while ((grp = gwlist_extract_first(list)) != NULL)
791 grp_dump(grp);
792 gwlist_destroy(list, NULL);
793 octstr_destroy(name);
794 }
795 gwlist_destroy(names, NULL);
796
797 debug("gwlib.cfg", 0, "Dump ends.");
798 }
799
800
cfg_dump_all(void)801 void cfg_dump_all(void)
802 {
803 #define OCTSTR(name) \
804 printf("%s = <please consult user doc>\n", #name);
805 #define SINGLE_GROUP(name, fields) \
806 printf("#\n# Single Group\n#\n"); \
807 printf("group = %s\n", #name); \
808 fields; \
809 printf("\n\n");
810 #define MULTI_GROUP(name, fields) \
811 printf("#\n# Multi Group\n#\n"); \
812 printf("group = %s\n", #name); \
813 fields; \
814 printf("\n\n");
815 #include "cfg.def"
816 }
817
818
cfg_init(void)819 void cfg_init(void)
820 {
821 /* make sure we put our own core hooks into the lists */
822 allowed_hooks = gwlist_create();
823 single_hooks = gwlist_create();
824
825 gwlist_append(allowed_hooks, &core_is_allowed_in_group);
826 gwlist_append(single_hooks, &core_is_single_group);
827 }
828
829
cfg_shutdown(void)830 void cfg_shutdown(void)
831 {
832 gwlist_destroy(allowed_hooks, NULL);
833 gwlist_destroy(single_hooks, NULL);
834 allowed_hooks = single_hooks = NULL;
835 }
836