Kannel: Open Source WAP and SMS gateway  $Revision: 5037 $
cfg.c
Go to the documentation of this file.
1 /* ====================================================================
2  * The Kannel Software License, Version 1.0
3  *
4  * Copyright (c) 2001-2016 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 {
77  long line;
78 };
79 
80 
81 static CfgGroup *create_group(void)
82 {
83  CfgGroup *grp;
84 
85  grp = gw_malloc(sizeof(*grp));
86  grp->name = NULL;
88  grp->configfile = NULL;
89  grp->line = 0;
90  return grp;
91 }
92 
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 {
109  long line_no;
111 };
112 
113 
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 
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 
136 static void destroy_group_list(void *arg)
137 {
139 }
140 
141 
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 static int octstr_sort_cb(const void *a, const void *b)
150 {
151  const Octstr *fa = a;
152  const Octstr *fb = b;
153 
154  return octstr_compare(fa, fb);
155 }
156 
157 
158 static int octstr_cmp_cb(void *a, void *b)
159 {
160  return (octstr_compare((Octstr*)a, (Octstr*)b) == 0);
161 }
162 
163 
164 struct Cfg {
168 };
169 
170 
171 /********************************************************************
172  * Section providing hooks to external modules to apply their specific
173  * is_allowed_in_group() and is_single_group() with their own
174  * foobar-cfg.def.
175  */
176 
179 
180 static int core_is_allowed_in_group(Octstr *group, Octstr *variable)
181 {
182  Octstr *groupstr;
183 
184  groupstr = octstr_imm("group");
185 
186  #define OCTSTR(name) \
187  if (octstr_compare(octstr_imm(#name), variable) == 0) \
188  return 1;
189  #define SINGLE_GROUP(name, fields) \
190  if (octstr_compare(octstr_imm(#name), group) == 0) { \
191  if (octstr_compare(groupstr, variable) == 0) \
192  return 1; \
193  fields \
194  return 0; \
195  }
196  #define MULTI_GROUP(name, fields) \
197  if (octstr_compare(octstr_imm(#name), group) == 0) { \
198  if (octstr_compare(groupstr, variable) == 0) \
199  return 1; \
200  fields \
201  return 0; \
202  }
203  #include "cfg.def"
204 
205  /* unknown group identifier */
206  return -1;
207 }
208 
209 
210 static int core_is_single_group(Octstr *query)
211 {
212  #define OCTSTR(name)
213  #define SINGLE_GROUP(name, fields) \
214  if (octstr_compare(octstr_imm(#name), query) == 0) \
215  return 1;
216  #define MULTI_GROUP(name, fields) \
217  if (octstr_compare(octstr_imm(#name), query) == 0) \
218  return 0;
219  #include "cfg.def"
220  return 0;
221 }
222 
223 
224 static int is_allowed_in_group(Octstr *group, Octstr *variable)
225 {
226  long i;
227  int x, r = -1;
228 
229  for (i = 0; i < gwlist_len(allowed_hooks); ++i) {
230  x = ((int(*)(Octstr *, Octstr *))
231  gwlist_get(allowed_hooks, i))(group, variable);
232  r = (x == -1 ? (r == -1 ? x : r) : (r == -1 ? x : r + x));
233  }
234 
235  return r;
236 }
237 
238 
239 static int is_single_group(Octstr *query)
240 {
241  long i;
242  int r = 0;
243 
244  for (i = 0; i < gwlist_len(single_hooks); ++i) {
245  r += ((int(*)(Octstr *))
246  gwlist_get(single_hooks, i))(query);
247  }
248 
249  return (r > 0);
250 }
251 
252 
253 void cfg_add_hooks(void *allowed, void *single)
254 {
255  gwlist_append(allowed_hooks, allowed);
256  gwlist_append(single_hooks, single);
257 }
258 
259 
260 static int add_group(Cfg *cfg, CfgGroup *grp)
261 {
262  Octstr *groupname;
263  Octstr *name;
264  List *names;
265  List *list;
266 
267  groupname = cfg_get(grp, octstr_imm("group"));
268  if (groupname == NULL) {
269  error(0, "Group does not contain variable 'group'.");
270  return -1;
271  }
272  set_group_name(grp, groupname);
273 
274  names = dict_keys(grp->vars);
275 
276  while ((name = gwlist_extract_first(names)) != NULL) {
277  int a = is_allowed_in_group(groupname, name);
278  switch (a) {
279  case 0:
280  error(0, "Group '%s' may not contain field '%s'.",
281  octstr_get_cstr(groupname), octstr_get_cstr(name));
282  octstr_destroy(name);
283  octstr_destroy(groupname);
285  return -1;
286  break;
287  case -1:
288  error(0, "Group '%s' is no valid group identifier.",
289  octstr_get_cstr(groupname));
290  octstr_destroy(name);
291  octstr_destroy(groupname);
293  return -1;
294  break;
295  default:
296  octstr_destroy(name);
297  break;
298  }
299  }
300  gwlist_destroy(names, NULL);
301 
302  if (is_single_group(groupname)) {
303  dict_put(cfg->single_groups, groupname, grp);
304  } else {
305  list = dict_get(cfg->multi_groups, groupname);
306  if (list == NULL) {
307  list = gwlist_create();
308  dict_put(cfg->multi_groups, groupname, list);
309  }
310  gwlist_append(list, grp);
311  }
312 
313  octstr_destroy(groupname);
314  return 0;
315 }
316 
317 
319 {
320  Cfg *cfg;
321 
322  cfg = gw_malloc(sizeof(*cfg));
323  cfg->filename = octstr_duplicate(filename);
326 
327  return cfg;
328 }
329 
330 
332 {
333  if (cfg != NULL) {
334  octstr_destroy(cfg->filename);
337  gw_free(cfg);
338  }
339 }
340 
341 
342 static void parse_value(Octstr *value)
343 {
344  Octstr *temp;
345  long len;
346  int c;
347 
348  octstr_strip_blanks(value);
349 
350  len = octstr_len(value);
351  if (octstr_get_char(value, 0) != '"' ||
352  octstr_get_char(value, len - 1) != '"')
353  return;
354 
355  octstr_delete(value, len - 1, 1);
356  octstr_delete(value, 0, 1);
357 
358  temp = octstr_duplicate(value);
359  octstr_truncate(value, 0);
360 
361  while (octstr_len(temp) > 0) {
362  c = octstr_get_char(temp, 0);
363  octstr_delete(temp, 0, 1);
364 
365  if (c != '\\' || octstr_len(temp) == 0)
366  octstr_append_char(value, c);
367  else {
368  c = octstr_get_char(temp, 0);
369  octstr_delete(temp, 0, 1);
370 
371  switch (c) {
372  case '\\':
373  case '"':
374  octstr_append_char(value, c);
375  break;
376 
377  default:
378  octstr_append_char(value, '\\');
379  octstr_append_char(value, c);
380  break;
381  }
382  }
383  }
384 
385  octstr_destroy(temp);
386 }
387 
388 
389 static List *expand_file(Octstr *file, int forward)
390 {
391  Octstr *os;
392  Octstr *line;
393  List *lines;
394  List *expand;
395  long lineno;
396  CfgLoc *loc = NULL;
397 
398  os = octstr_read_file(octstr_get_cstr(file));
399  if (os == NULL)
400  return NULL;
401 
402  lines = octstr_split(os, octstr_imm("\n"));
403  lineno = 0;
404  expand = gwlist_create();
405 
406  while ((line = gwlist_extract_first(lines)) != NULL) {
407  if (loc == NULL) {
408  ++lineno;
409  loc = cfgloc_create(file);
410  loc->line_no = lineno;
411  loc->line = octstr_create("");
412  if (forward)
413  gwlist_append(expand, loc);
414  else
415  gwlist_insert(expand, 0, loc);
416  }
417  /* check for escape and then add to existing loc */
418  if (octstr_get_char(line, octstr_len(line) - 1) == '\\') {
419  octstr_delete(line, octstr_len(line) - 1, 1);
420  octstr_append(loc->line, line);
421  /* check for second escape */
422  if (octstr_get_char(line, octstr_len(line) - 1) == '\\')
423  loc = NULL;
424  } else {
425  octstr_append(loc->line, line);
426  loc = NULL;
427  }
428  octstr_destroy(line);
429  }
430 
431  /*
432  * add newline at each end of included files to avoid
433  * concatenating different groups by mistake
434  */
435  if (lineno > 0) {
436  loc = cfgloc_create(file);
437  loc->line_no = lineno;
438  loc->line = octstr_create("\n");
439  if (forward)
440  gwlist_append(expand, loc);
441  else
442  gwlist_insert(expand, 0, loc);
443  }
444 
446  octstr_destroy(os);
447 
448  return expand;
449 }
450 
451 
453 {
454  CfgLoc *loc;
455  CfgLoc *loc_inc;
456  List *lines;
457  List *expand;
458  List *stack;
459  Octstr *name;
460  Octstr *value;
461  Octstr *filename;
462  CfgGroup *grp;
463  long equals;
464  long error_lineno;
465 
466  loc = loc_inc = NULL;
467 
468  /*
469  * expand initial main config file and add it to the recursion
470  * stack to protect against cycling
471  */
472  if ((lines = expand_file(cfg->filename, 1)) == NULL) {
473  panic(0, "Failed to load main configuration file `%s'. Aborting!",
474  octstr_get_cstr(cfg->filename));
475  }
476  stack = gwlist_create();
477  gwlist_insert(stack, 0, octstr_duplicate(cfg->filename));
478 
479  grp = NULL;
480  error_lineno = 0;
481  while (error_lineno == 0 && (loc = gwlist_extract_first(lines)) != NULL) {
482  octstr_strip_blanks(loc->line);
483  if (octstr_len(loc->line) == 0) {
484  if (grp != NULL && add_group(cfg, grp) == -1) {
485  error_lineno = loc->line_no;
486  destroy_group(grp);
487  }
488  grp = NULL;
489  } else if (octstr_get_char(loc->line, 0) != '#') {
490  equals = octstr_search_char(loc->line, '=', 0);
491  if (equals == -1) {
492  error(0, "An equals sign ('=') is missing on line %ld of file %s.",
493  loc->line_no, octstr_get_cstr(loc->filename));
494  error_lineno = loc->line_no;
495  } else
496 
497  /*
498  * check for special config directives, like include or conditional
499  * directives here
500  */
501  if (octstr_search(loc->line, octstr_imm("include"), 0) != -1) {
502  filename = octstr_copy(loc->line, equals + 1, octstr_len(loc->line));
503  parse_value(filename);
504 
505  /* check if we are cycling */
506  if (gwlist_search(stack, filename, octstr_item_match) != NULL) {
507  panic(0, "Recursive include for config file `%s' detected "
508  "(on line %ld of file %s).",
509  octstr_get_cstr(filename), loc->line_no,
510  octstr_get_cstr(loc->filename));
511  } else {
512  List *files = gwlist_create();
513  Octstr *file;
514  struct stat filestat;
515 
516  /* check if included file is a directory */
517  if (lstat(octstr_get_cstr(filename), &filestat) != 0) {
518  error(errno, "lstat failed: couldn't stat `%s'",
519  octstr_get_cstr(filename));
520  panic(0, "Failed to include `%s' "
521  "(on line %ld of file %s). Aborting!",
522  octstr_get_cstr(filename), loc->line_no,
523  octstr_get_cstr(loc->filename));
524  }
525 
526  /*
527  * is a directory, create a list with files of
528  * this directory and load all as part of the
529  * whole configuration.
530  */
531  if (S_ISDIR(filestat.st_mode)) {
532  DIR *dh;
533  struct dirent *diritem;
534 
535  debug("gwlib.cfg", 0, "Loading include dir `%s' "
536  "(on line %ld of file %s).",
537  octstr_get_cstr(filename), loc->line_no,
538  octstr_get_cstr(loc->filename));
539 
540  dh = opendir(octstr_get_cstr(filename));
541  while ((diritem = readdir(dh))) {
542  Octstr *fileitem;
543 
544  fileitem = octstr_duplicate(filename);
545  octstr_append_cstr(fileitem, "/");
546  octstr_append_cstr(fileitem, diritem->d_name);
547 
548  lstat(octstr_get_cstr(fileitem), &filestat);
549  if (!S_ISDIR(filestat.st_mode)) {
550  gwlist_insert(files, 0, fileitem);
551  } else {
552  octstr_destroy(fileitem);
553  }
554  }
555  closedir(dh);
556  }
557 
558  /* is a file, create a list with it */
559  else {
560  gwlist_insert(files, 0, octstr_duplicate(filename));
561  }
562 
563  /* include files */
564  while ((file = gwlist_extract_first(files)) != NULL) {
565 
566  gwlist_insert(stack, 0, octstr_duplicate(file));
567  debug("gwlib.cfg", 0, "Loading include file `%s' (on line %ld of file %s).",
568  octstr_get_cstr(file), loc->line_no,
569  octstr_get_cstr(loc->filename));
570 
571  /*
572  * expand the given include file and add it to the current
573  * processed main while loop
574  */
575  if ((expand = expand_file(file, 0)) != NULL) {
576  while ((loc_inc = gwlist_extract_first(expand)) != NULL)
577  gwlist_insert(lines, 0, loc_inc);
578  } else {
579  panic(0, "Failed to load whole configuration. Aborting!");
580  }
581 
582  gwlist_destroy(expand, NULL);
583  cfgloc_destroy(loc_inc);
584  octstr_destroy(file);
585  }
587  }
588  octstr_destroy(filename);
589  }
590 
591  /*
592  * this is a "normal" line, so process it accodingly
593  */
594  else {
595  name = octstr_copy(loc->line, 0, equals);
596  octstr_strip_blanks(name);
597  value = octstr_copy(loc->line, equals + 1, octstr_len(loc->line));
598  parse_value(value);
599 
600  if (grp == NULL)
601  grp = create_group();
602 
603  if (grp->configfile != NULL) {
604  octstr_destroy(grp->configfile);
605  grp->configfile = NULL;
606  }
607  grp->configfile = octstr_duplicate(cfg->filename);
608 
609  cfg_set(grp, name, value);
610  octstr_destroy(name);
611  octstr_destroy(value);
612  }
613  }
614 
615  cfgloc_destroy(loc);
616  }
617 
618  if (grp != NULL && add_group(cfg, grp) == -1) {
619  error_lineno = 1;
620  destroy_group(grp);
621  }
622 
623  gwlist_destroy(lines, NULL);
625 
626  if (error_lineno != 0) {
627  error(0, "Error found on line %ld of file `%s'.",
628  error_lineno, octstr_get_cstr(cfg->filename));
629  return -1;
630  }
631 
632  return 0;
633 }
634 
635 
637 {
638  return dict_get(cfg->single_groups, name);
639 }
640 
641 
643 {
644  List *list, *copy;
645  long i;
646 
647  list = dict_get(cfg->multi_groups, name);
648  if (list == NULL)
649  return NULL;
650 
651  copy = gwlist_create();
652  for (i = 0; i < gwlist_len(list); ++i)
653  gwlist_append(copy, gwlist_get(list, i));
654  return copy;
655 }
656 
657 
659 {
660  return octstr_duplicate(grp->name);
661 }
662 
664 {
665  va_list args;
666  Octstr *ret, *os, *key, *val;
667  List *exclude, *keys;
668 
669  exclude = gwlist_create();
670 
671  /*
672  * Variadic Octstr* arguments may contain the
673  * config key names that DO NOT go into the
674  * checksum computation. This allows differential
675  * compares and detection of single changes.
676  */
677  va_start(args, grp);
678  while ((os = va_arg(args, Octstr*)) != NULL) {
679  gwlist_append(exclude, os);
680  }
681  va_end(args);
682 
683  /* all configured config names of this group */
684  keys = dict_keys(grp->vars);
685 
686  /* remove all excluded configs names */
687  while ((os = gwlist_extract_first(exclude)) != NULL) {
688  if ((key = gwlist_search(keys, os, octstr_cmp_cb)) != NULL) {
689  if (gwlist_delete_equal(keys, key) != 1)
690  panic(0, "%s: multiple config variables with same name `%s'?!", __func__,
691  octstr_get_cstr(key));
692  octstr_destroy(key);
693  }
694  }
695  gwlist_destroy(exclude, NULL);
696 
697  os = octstr_duplicate(grp->name);
699  while ((key = gwlist_extract_first(keys)) != NULL) {
700  octstr_append(os, key);
701  if ((val = dict_get(grp->vars, key)) != NULL)
702  octstr_append(os, val);
703  octstr_destroy(key);
704  }
705  gwlist_destroy(keys, NULL);
706 
707  ret = md5(os);
708  octstr_destroy(os);
709 
710  return ret;
711 }
712 
714 {
715  return octstr_duplicate(grp->configfile);
716 }
717 
718 
719 Octstr *cfg_get_real(CfgGroup *grp, Octstr *varname, const char *file,
720  long line, const char *func)
721 {
722  Octstr *os;
723 
724  if(grp == NULL)
725  panic(0, "Trying to fetch variable `%s' in non-existing group",
726  octstr_get_cstr(varname));
727 
728  if (grp->name != NULL && !is_allowed_in_group(grp->name, varname))
729  panic(0, "Trying to fetch variable `%s' in group `%s', not allowed.",
730  octstr_get_cstr(varname), octstr_get_cstr(grp->name));
731 
732  os = dict_get(grp->vars, varname);
733  if (os == NULL)
734  return NULL;
735  return gw_claim_area_for(octstr_duplicate(os), file, line, func);
736 }
737 
738 
739 int cfg_get_integer(long *n, CfgGroup *grp, Octstr *varname)
740 {
741  Octstr *os;
742  int ret;
743 
744  os = cfg_get(grp, varname);
745  if (os == NULL)
746  return -1;
747  if (octstr_parse_long(n, os, 0, 0) == -1)
748  ret = -1;
749  else
750  ret = 0;
751  octstr_destroy(os);
752  return ret;
753 }
754 
755 
756 int cfg_get_bool(int *n, CfgGroup *grp, Octstr *varname)
757 {
758  Octstr *os;
759 
760  os = cfg_get(grp, varname);
761  if (os == NULL) {
762  *n = 0;
763  return -1;
764  }
765  if (octstr_case_compare(os, octstr_imm("true")) == 0
766  || octstr_case_compare(os, octstr_imm("yes")) == 0
767  || octstr_case_compare(os, octstr_imm("on")) == 0
768  || octstr_case_compare(os, octstr_imm("1")) == 0)
769  {
770  *n = 1;
771  } else if (octstr_case_compare(os, octstr_imm("false")) == 0
772  || octstr_case_compare(os, octstr_imm("no")) == 0
773  || octstr_case_compare(os, octstr_imm("off")) == 0
774  || octstr_case_compare(os, octstr_imm("0")) == 0)
775  {
776  *n = 0;
777  }
778  else {
779  *n = 1;
780  warning(0, "bool variable set to strange value, assuming 'true'");
781  }
782  octstr_destroy(os);
783  return 0;
784 }
785 
786 
788 {
789  Octstr *os;
790  List *list;
791 
792  os = cfg_get(grp, varname);
793  if (os == NULL)
794  return NULL;
795 
796  list = octstr_split_words(os);
797  octstr_destroy(os);
798  return list;
799 }
800 
801 
802 void cfg_set(CfgGroup *grp, Octstr *varname, Octstr *value)
803 {
804  dict_put(grp->vars, varname, octstr_duplicate(value));
805 }
806 
807 
808 void grp_dump(CfgGroup *grp)
809 {
810  List *names;
811  Octstr *name;
812  Octstr *value;
813 
814  if (grp->name == NULL)
815  debug("gwlib.cfg", 0, " dumping group (name not set):");
816  else
817  debug("gwlib.cfg", 0, " dumping group (%s):",
818  octstr_get_cstr(grp->name));
819  names = dict_keys(grp->vars);
820  while ((name = gwlist_extract_first(names)) != NULL) {
821  value = cfg_get(grp, name);
822  debug("gwlib.cfg", 0, " <%s> = <%s>",
823  octstr_get_cstr(name),
824  octstr_get_cstr(value));
825  octstr_destroy(value);
826  octstr_destroy(name);
827  }
828  gwlist_destroy(names, NULL);
829 }
830 
831 
833 {
834  CfgGroup *grp;
835  List *list;
836  List *names;
837  Octstr *name;
838 
839  debug("gwlib.cfg", 0, "Dumping Cfg %p", (void *) cfg);
840  debug("gwlib.cfg", 0, " filename = <%s>",
841  octstr_get_cstr(cfg->filename));
842 
843  names = dict_keys(cfg->single_groups);
844  while ((name = gwlist_extract_first(names)) != NULL) {
845  grp = cfg_get_single_group(cfg, name);
846  if (grp != NULL)
847  grp_dump(grp);
848  octstr_destroy(name);
849  }
850  gwlist_destroy(names, NULL);
851 
852  names = dict_keys(cfg->multi_groups);
853  while ((name = gwlist_extract_first(names)) != NULL) {
854  list = cfg_get_multi_group(cfg, name);
855  while ((grp = gwlist_extract_first(list)) != NULL)
856  grp_dump(grp);
857  gwlist_destroy(list, NULL);
858  octstr_destroy(name);
859  }
860  gwlist_destroy(names, NULL);
861 
862  debug("gwlib.cfg", 0, "Dump ends.");
863 }
864 
865 
866 void cfg_dump_all(void)
867 {
868  #define OCTSTR(name) \
869  printf("%s = <please consult user doc>\n", #name);
870  #define SINGLE_GROUP(name, fields) \
871  printf("#\n# Single Group\n#\n"); \
872  printf("group = %s\n", #name); \
873  fields; \
874  printf("\n\n");
875  #define MULTI_GROUP(name, fields) \
876  printf("#\n# Multi Group\n#\n"); \
877  printf("group = %s\n", #name); \
878  fields; \
879  printf("\n\n");
880  #include "cfg.def"
881 }
882 
883 
884 void cfg_init(void)
885 {
886  /* make sure we put our own core hooks into the lists */
887  allowed_hooks = gwlist_create();
888  single_hooks = gwlist_create();
889 
890  gwlist_append(allowed_hooks, &core_is_allowed_in_group);
891  gwlist_append(single_hooks, &core_is_single_group);
892 }
893 
894 
895 void cfg_shutdown(void)
896 {
897  gwlist_destroy(allowed_hooks, NULL);
898  gwlist_destroy(single_hooks, NULL);
899  allowed_hooks = single_hooks = NULL;
900 }
Dict * dict_create(long size_hint, void(*destroy_value)(void *))
Definition: dict.c:192
void error(int err, const char *fmt,...)
Definition: log.c:612
Octstr * md5(Octstr *data)
Definition: md5.c:387
void * gwlist_search(List *list, void *pattern, int(*cmp)(void *, void *))
Definition: list.c:486
static List * expand_file(Octstr *file, int forward)
Definition: cfg.c:389
Octstr * filename
Definition: cfg.c:108
static int add_group(Cfg *cfg, CfgGroup *grp)
Definition: cfg.c:260
void dict_put(Dict *dict, Octstr *key, void *value)
Definition: dict.c:240
void gwlist_append(List *list, void *item)
Definition: list.c:179
static void cfgloc_destroy(CfgLoc *cfgloc)
Definition: cfg.c:126
static List * allowed_hooks
Definition: cfg.c:177
void octstr_append(Octstr *ostr1, const Octstr *ostr2)
Definition: octstr.c:1502
List * cfg_get_list(CfgGroup *grp, Octstr *varname)
Definition: cfg.c:787
long gwlist_len(List *list)
Definition: list.c:166
static void destroy_group_list(void *arg)
Definition: cfg.c:136
Octstr * cfg_get_configfile(CfgGroup *grp)
Definition: cfg.c:713
void * gwlist_get(List *list, long pos)
Definition: list.c:292
void gwlist_sort(List *list, int(*cmp)(const void *, const void *))
Definition: list.c:576
static CfgLoc * cfgloc_create(Octstr *filename)
Definition: cfg.c:114
static int core_is_single_group(Octstr *query)
Definition: cfg.c:210
void octstr_append_char(Octstr *ostr, int ch)
Definition: octstr.c:1515
Octstr * name
Definition: cfg.c:74
Octstr * cfg_get_group_checksum(CfgGroup *grp,...)
Definition: cfg.c:663
long octstr_search(const Octstr *haystack, const Octstr *needle, long pos)
Definition: octstr.c:1068
#define cfg_get(grp, varname)
Definition: cfg.h:86
void octstr_append_cstr(Octstr *ostr, const char *cstr)
Definition: octstr.c:1509
void octstr_strip_blanks(Octstr *text)
Definition: octstr.c:1344
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
#define octstr_copy(ostr, from, len)
Definition: octstr.h:178
long octstr_search_char(const Octstr *ostr, int ch, long pos)
Definition: octstr.c:1010
static List * lines
Definition: mtbatch.c:88
Definition: cfg.c:107
FILE * file
Definition: log.c:133
Dict * multi_groups
Definition: cfg.c:167
Cfg * cfg_create(Octstr *filename)
Definition: cfg.c:318
static int octstr_cmp_cb(void *a, void *b)
Definition: cfg.c:158
int cfg_read(Cfg *cfg)
Definition: cfg.c:452
void cfg_shutdown(void)
Definition: cfg.c:895
Octstr * octstr_imm(const char *cstr)
Definition: octstr.c:281
void cfg_add_hooks(void *allowed, void *single)
Definition: cfg.c:253
Definition: cfg.c:164
void cfg_destroy(Cfg *cfg)
Definition: cfg.c:331
void * gwlist_extract_first(List *list)
Definition: list.c:305
Octstr * cfg_get_real(CfgGroup *grp, Octstr *varname, const char *file, long line, const char *func)
Definition: cfg.c:719
void grp_dump(CfgGroup *grp)
Definition: cfg.c:808
void * dict_get(Dict *dict, Octstr *key)
Definition: dict.c:286
void octstr_delete(Octstr *ostr1, long pos, long len)
Definition: octstr.c:1525
static int octstr_sort_cb(const void *a, const void *b)
Definition: cfg.c:149
static int core_is_allowed_in_group(Octstr *group, Octstr *variable)
Definition: cfg.c:180
void cfg_dump(Cfg *cfg)
Definition: cfg.c:832
Definition: dict.c:116
#define octstr_duplicate(ostr)
Definition: octstr.h:187
List * cfg_get_multi_group(Cfg *cfg, Octstr *name)
Definition: cfg.c:642
static void destroy_group(void *arg)
Definition: cfg.c:93
long gwlist_delete_equal(List *list, void *item)
Definition: list.c:266
int octstr_item_match(void *item, void *pattern)
Definition: octstr.c:1659
char * name
Definition: smsc_cimd2.c:212
int octstr_case_compare(const Octstr *os1, const Octstr *os2)
Definition: octstr.c:901
void warning(int err, const char *fmt,...)
Definition: log.c:624
List * octstr_split_words(const Octstr *ostr)
Definition: octstr.c:1600
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:322
static List * single_hooks
Definition: cfg.c:178
char filename[FILENAME_MAX+1]
Definition: log.c:135
#define octstr_create(cstr)
Definition: octstr.h:125
void octstr_destroy_item(void *os)
Definition: octstr.c:334
void cfg_dump_all(void)
Definition: cfg.c:866
long line
Definition: cfg.c:77
void gwlist_insert(List *list, long pos, void *item)
Definition: list.c:214
void cfg_set(CfgGroup *grp, Octstr *varname, Octstr *value)
Definition: cfg.c:802
Octstr * octstr_read_file(const char *filename)
Definition: octstr.c:1546
static Cfg * cfg
Definition: smsbox.c:115
Octstr * cfg_get_group_name(CfgGroup *grp)
Definition: cfg.c:658
long octstr_len(const Octstr *ostr)
Definition: octstr.c:340
void dict_destroy(Dict *dict)
Definition: dict.c:215
int cfg_get_bool(int *n, CfgGroup *grp, Octstr *varname)
Definition: cfg.c:756
Definition: octstr.c:118
long line_no
Definition: cfg.c:109
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:690
int cfg_get_integer(long *n, CfgGroup *grp, Octstr *varname)
Definition: cfg.c:739
void cfg_init(void)
Definition: cfg.c:884
#define panic
Definition: log.h:87
static CfgGroup * create_group(void)
Definition: cfg.c:81
Definition: cfg.c:73
long octstr_parse_long(long *nump, Octstr *ostr, long pos, int base)
Definition: octstr.c:747
static int is_single_group(Octstr *query)
Definition: cfg.c:239
List * dict_keys(Dict *dict)
Definition: dict.c:347
#define gwlist_create()
Definition: list.h:136
void octstr_truncate(Octstr *ostr, int new_len)
Definition: octstr.c:1325
static void set_group_name(CfgGroup *grp, Octstr *name)
Definition: cfg.c:142
Octstr * filename
Definition: cfg.c:165
CfgGroup * cfg_get_single_group(Cfg *cfg, Octstr *name)
Definition: cfg.c:636
int octstr_get_char(const Octstr *ostr, long pos)
Definition: octstr.c:404
List * octstr_split(const Octstr *os, const Octstr *sep)
Definition: octstr.c:1638
Definition: list.c:102
Dict * vars
Definition: cfg.c:75
Octstr * configfile
Definition: cfg.c:76
Octstr * line
Definition: cfg.c:110
Dict * single_groups
Definition: cfg.c:166
int octstr_compare(const Octstr *ostr1, const Octstr *ostr2)
Definition: octstr.c:869
static int is_allowed_in_group(Octstr *group, Octstr *variable)
Definition: cfg.c:224
static void parse_value(Octstr *value)
Definition: cfg.c:342
void gwlist_destroy(List *list, gwlist_item_destructor_t *destructor)
Definition: list.c:145
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.