Add support for a realtime sorcery module.
[asterisk/asterisk.git] / main / config.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2010, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief Configuration File Parser
22  *
23  * \author Mark Spencer <markster@digium.com>
24  *
25  * Includes the Asterisk Realtime API - ARA
26  * See http://wiki.asterisk.org
27  */
28
29 /*** MODULEINFO
30         <support_level>core</support_level>
31  ***/
32
33 #include "asterisk.h"
34
35 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
36
37 #include "asterisk/paths.h"     /* use ast_config_AST_CONFIG_DIR */
38 #include "asterisk/network.h"   /* we do some sockaddr manipulation here */
39 #include <time.h>
40 #include <sys/stat.h>
41
42 #include <math.h>       /* HUGE_VAL */
43
44 #define AST_INCLUDE_GLOB 1
45
46 #include "asterisk/config.h"
47 #include "asterisk/cli.h"
48 #include "asterisk/lock.h"
49 #include "asterisk/utils.h"
50 #include "asterisk/channel.h"
51 #include "asterisk/app.h"
52 #include "asterisk/astobj2.h"
53 #include "asterisk/strings.h"   /* for the ast_str_*() API */
54 #include "asterisk/netsock2.h"
55
56 #define MAX_NESTED_COMMENTS 128
57 #define COMMENT_START ";--"
58 #define COMMENT_END "--;"
59 #define COMMENT_META ';'
60 #define COMMENT_TAG '-'
61
62 /*!
63  * Define the minimum filename space to reserve for each
64  * ast_variable in case the filename is renamed later by
65  * ast_include_rename().
66  */
67 #define MIN_VARIABLE_FNAME_SPACE        40
68
69 static char *extconfig_conf = "extconfig.conf";
70
71 static struct ao2_container *cfg_hooks;
72 static void config_hook_exec(const char *filename, const char *module, struct ast_config *cfg);
73
74 /*! \brief Structure to keep comments for rewriting configuration files */
75 struct ast_comment {
76         struct ast_comment *next;
77         /*! Comment body allocated after struct. */
78         char cmt[0];
79 };
80
81 /*! \brief Hold the mtime for config files, so if we don't need to reread our config, don't. */
82 struct cache_file_include {
83         AST_LIST_ENTRY(cache_file_include) list;
84         char include[0];
85 };
86
87 struct cache_file_mtime {
88         AST_LIST_ENTRY(cache_file_mtime) list;
89         AST_LIST_HEAD_NOLOCK(includes, cache_file_include) includes;
90         unsigned int has_exec:1;
91         time_t mtime;
92
93         /*! String stuffed in filename[] after the filename string. */
94         const char *who_asked;
95         /*! Filename and who_asked stuffed after it. */
96         char filename[0];
97 };
98
99 /*! Cached file mtime list. */
100 static AST_LIST_HEAD_STATIC(cfmtime_head, cache_file_mtime);
101
102 static int init_appendbuf(void *data)
103 {
104         struct ast_str **str = data;
105         *str = ast_str_create(16);
106         return *str ? 0 : -1;
107 }
108
109 AST_THREADSTORAGE_CUSTOM(appendbuf, init_appendbuf, ast_free_ptr);
110
111 /* comment buffers are better implemented using the ast_str_*() API */
112 #define CB_SIZE 250     /* initial size of comment buffers */
113
114 static void  CB_ADD(struct ast_str **cb, const char *str)
115 {
116         ast_str_append(cb, 0, "%s", str);
117 }
118
119 static void  CB_ADD_LEN(struct ast_str **cb, const char *str, int len)
120 {
121         char *s = ast_alloca(len + 1);
122         ast_copy_string(s, str, len);
123         ast_str_append(cb, 0, "%s", str);
124 }
125
126 static void CB_RESET(struct ast_str *cb, struct ast_str *llb)
127 {
128         if (cb) {
129                 ast_str_reset(cb);
130         }
131         if (llb) {
132                 ast_str_reset(llb);
133         }
134 }
135
136 static struct ast_comment *ALLOC_COMMENT(struct ast_str *buffer)
137 {
138         struct ast_comment *x = NULL;
139         if (!buffer || !ast_str_strlen(buffer)) {
140                 return NULL;
141         }
142         if ((x = ast_calloc(1, sizeof(*x) + ast_str_strlen(buffer) + 1))) {
143                 strcpy(x->cmt, ast_str_buffer(buffer)); /* SAFE */
144         }
145         return x;
146 }
147
148 /* I need to keep track of each config file, and all its inclusions,
149    so that we can track blank lines in each */
150
151 struct inclfile {
152         char *fname;
153         int lineno;
154 };
155
156 static int hash_string(const void *obj, const int flags)
157 {
158         char *str = ((struct inclfile *) obj)->fname;
159         int total;
160
161         for (total = 0; *str; str++) {
162                 unsigned int tmp = total;
163                 total <<= 1; /* multiply by 2 */
164                 total += tmp; /* multiply by 3 */
165                 total <<= 2; /* multiply by 12 */
166                 total += tmp; /* multiply by 13 */
167
168                 total += ((unsigned int) (*str));
169         }
170         if (total < 0) {
171                 total = -total;
172         }
173         return total;
174 }
175
176 static int hashtab_compare_strings(void *a, void *b, int flags)
177 {
178         const struct inclfile *ae = a, *be = b;
179         return !strcmp(ae->fname, be->fname) ? CMP_MATCH | CMP_STOP : 0;
180 }
181
182 static struct ast_config_map {
183         struct ast_config_map *next;
184         int priority;
185         /*! Stored in stuff[] at struct end. */
186         const char *name;
187         /*! Stored in stuff[] at struct end. */
188         const char *driver;
189         /*! Stored in stuff[] at struct end. */
190         const char *database;
191         /*! Stored in stuff[] at struct end. */
192         const char *table;
193         /*! Contents of name, driver, database, and table in that order stuffed here. */
194         char stuff[0];
195 } *config_maps = NULL;
196
197 AST_MUTEX_DEFINE_STATIC(config_lock);
198 static struct ast_config_engine *config_engine_list;
199
200 #define MAX_INCLUDE_LEVEL 10
201
202 struct ast_category_template_instance {
203         char name[80]; /* redundant? */
204         const struct ast_category *inst;
205         AST_LIST_ENTRY(ast_category_template_instance) next;
206 };
207
208 struct ast_category {
209         char name[80];
210         int ignored;                    /*!< do not let user of the config see this category -- set by (!) after the category decl; a template */
211         int include_level;
212         /*!
213          * \brief The file name from whence this declaration was read
214          * \note Will never be NULL
215          */
216         char *file;
217         int lineno;
218         AST_LIST_HEAD_NOLOCK(template_instance_list, ast_category_template_instance) template_instances;
219         struct ast_comment *precomments;
220         struct ast_comment *sameline;
221         struct ast_comment *trailing; /*!< the last object in the list will get assigned any trailing comments when EOF is hit */
222         /*! First category variable in the list. */
223         struct ast_variable *root;
224         /*! Last category variable in the list. */
225         struct ast_variable *last;
226         /*! Next node in the list. */
227         struct ast_category *next;
228 };
229
230 struct ast_config {
231         /*! First config category in the list. */
232         struct ast_category *root;
233         /*! Last config category in the list. */
234         struct ast_category *last;
235         struct ast_category *current;
236         struct ast_category *last_browse;     /*!< used to cache the last category supplied via category_browse */
237         int include_level;
238         int max_include_level;
239         struct ast_config_include *includes;  /*!< a list of inclusions, which should describe the entire tree */
240 };
241
242 struct ast_config_include {
243         /*!
244          * \brief file name in which the include occurs
245          * \note Will never be NULL
246          */
247         char *include_location_file;
248         int  include_location_lineno;    /*!< lineno where include occurred */
249         int  exec;                       /*!< set to non-zero if its a #exec statement */
250         /*!
251          * \brief if it's an exec, you'll have both the /var/tmp to read, and the original script
252          * \note Will never be NULL if exec is non-zero
253          */
254         char *exec_file;
255         /*!
256          * \brief file name included
257          * \note Will never be NULL
258          */
259         char *included_file;
260         int inclusion_count;             /*!< if the file is included more than once, a running count thereof -- but, worry not,
261                                               we explode the instances and will include those-- so all entries will be unique */
262         int output;                      /*!< a flag to indicate if the inclusion has been output */
263         struct ast_config_include *next; /*!< ptr to next inclusion in the list */
264 };
265
266 static void ast_variable_destroy(struct ast_variable *doomed);
267 static void ast_includes_destroy(struct ast_config_include *incls);
268
269 #ifdef MALLOC_DEBUG
270 struct ast_variable *_ast_variable_new(const char *name, const char *value, const char *filename, const char *file, const char *func, int lineno)
271 #else
272 struct ast_variable *ast_variable_new(const char *name, const char *value, const char *filename)
273 #endif
274 {
275         struct ast_variable *variable;
276         int name_len = strlen(name) + 1;
277         int val_len = strlen(value) + 1;
278         int fn_len = strlen(filename) + 1;
279
280         /* Ensure a minimum length in case the filename is changed later. */
281         if (fn_len < MIN_VARIABLE_FNAME_SPACE) {
282                 fn_len = MIN_VARIABLE_FNAME_SPACE;
283         }
284
285         if (
286 #ifdef MALLOC_DEBUG
287                 (variable = __ast_calloc(1, fn_len + name_len + val_len + sizeof(*variable), file, lineno, func))
288 #else
289                 (variable = ast_calloc(1, fn_len + name_len + val_len + sizeof(*variable)))
290 #endif
291                 ) {
292                 char *dst = variable->stuff;    /* writable space starts here */
293
294                 /* Put file first so ast_include_rename() can calculate space available. */
295                 variable->file = strcpy(dst, filename);
296                 dst += fn_len;
297                 variable->name = strcpy(dst, name);
298                 dst += name_len;
299                 variable->value = strcpy(dst, value);
300         }
301         return variable;
302 }
303
304 /*!
305  * \internal
306  * \brief Move the contents from the source to the destination variable.
307  *
308  * \param dst_var Destination variable node
309  * \param src_var Source variable node
310  *
311  * \return Nothing
312  */
313 static void ast_variable_move(struct ast_variable *dst_var, struct ast_variable *src_var)
314 {
315         dst_var->lineno = src_var->lineno;
316         dst_var->object = src_var->object;
317         dst_var->blanklines = src_var->blanklines;
318         dst_var->precomments = src_var->precomments;
319         src_var->precomments = NULL;
320         dst_var->sameline = src_var->sameline;
321         src_var->sameline = NULL;
322         dst_var->trailing = src_var->trailing;
323         src_var->trailing = NULL;
324 }
325
326 struct ast_config_include *ast_include_new(struct ast_config *conf, const char *from_file, const char *included_file, int is_exec, const char *exec_file, int from_lineno, char *real_included_file_name, int real_included_file_name_size)
327 {
328         /* a file should be included ONCE. Otherwise, if one of the instances is changed,
329          * then all be changed. -- how do we know to include it? -- Handling modified
330          * instances is possible, I'd have
331          * to create a new master for each instance. */
332         struct ast_config_include *inc;
333         struct stat statbuf;
334
335         inc = ast_include_find(conf, included_file);
336         if (inc) {
337                 do {
338                         inc->inclusion_count++;
339                         snprintf(real_included_file_name, real_included_file_name_size, "%s~~%d", included_file, inc->inclusion_count);
340                 } while (stat(real_included_file_name, &statbuf) == 0);
341                 ast_log(LOG_WARNING,"'%s', line %d:  Same File included more than once! This data will be saved in %s if saved back to disk.\n", from_file, from_lineno, real_included_file_name);
342         } else
343                 *real_included_file_name = 0;
344
345         inc = ast_calloc(1,sizeof(struct ast_config_include));
346         if (!inc) {
347                 return NULL;
348         }
349         inc->include_location_file = ast_strdup(from_file);
350         inc->include_location_lineno = from_lineno;
351         if (!ast_strlen_zero(real_included_file_name))
352                 inc->included_file = ast_strdup(real_included_file_name);
353         else
354                 inc->included_file = ast_strdup(included_file);
355
356         inc->exec = is_exec;
357         if (is_exec)
358                 inc->exec_file = ast_strdup(exec_file);
359
360         if (!inc->include_location_file
361                 || !inc->included_file
362                 || (is_exec && !inc->exec_file)) {
363                 ast_includes_destroy(inc);
364                 return NULL;
365         }
366
367         /* attach this new struct to the conf struct */
368         inc->next = conf->includes;
369         conf->includes = inc;
370
371         return inc;
372 }
373
374 void ast_include_rename(struct ast_config *conf, const char *from_file, const char *to_file)
375 {
376         struct ast_config_include *incl;
377         struct ast_category *cat;
378         char *str;
379
380         int from_len = strlen(from_file);
381         int to_len = strlen(to_file);
382
383         if (strcmp(from_file, to_file) == 0) /* no use wasting time if the name is the same */
384                 return;
385
386         /* the manager code allows you to read in one config file, then
387          * write it back out under a different name. But, the new arrangement
388          * ties output lines to the file name. So, before you try to write
389          * the config file to disk, better riffle thru the data and make sure
390          * the file names are changed.
391          */
392         /* file names are on categories, includes (of course), and on variables. So,
393          * traverse all this and swap names */
394
395         for (incl = conf->includes; incl; incl=incl->next) {
396                 if (strcmp(incl->include_location_file,from_file) == 0) {
397                         if (from_len >= to_len)
398                                 strcpy(incl->include_location_file, to_file);
399                         else {
400                                 /* Keep the old filename if the allocation fails. */
401                                 str = ast_strdup(to_file);
402                                 if (str) {
403                                         ast_free(incl->include_location_file);
404                                         incl->include_location_file = str;
405                                 }
406                         }
407                 }
408         }
409         for (cat = conf->root; cat; cat = cat->next) {
410                 struct ast_variable **prev;
411                 struct ast_variable *v;
412                 struct ast_variable *new_var;
413
414                 if (strcmp(cat->file,from_file) == 0) {
415                         if (from_len >= to_len)
416                                 strcpy(cat->file, to_file);
417                         else {
418                                 /* Keep the old filename if the allocation fails. */
419                                 str = ast_strdup(to_file);
420                                 if (str) {
421                                         ast_free(cat->file);
422                                         cat->file = str;
423                                 }
424                         }
425                 }
426                 for (prev = &cat->root, v = cat->root; v; prev = &v->next, v = v->next) {
427                         if (strcmp(v->file, from_file)) {
428                                 continue;
429                         }
430
431                         /*
432                          * Calculate actual space available.  The file string is
433                          * intentionally stuffed before the name string just so we can
434                          * do this.
435                          */
436                         if (to_len < v->name - v->file) {
437                                 /* The new name will fit in the available space. */
438                                 str = (char *) v->file;/* Stupid compiler complains about discarding qualifiers even though I used a cast. */
439                                 strcpy(str, to_file);/* SAFE */
440                                 continue;
441                         }
442
443                         /* Keep the old filename if the allocation fails. */
444                         new_var = ast_variable_new(v->name, v->value, to_file);
445                         if (!new_var) {
446                                 continue;
447                         }
448
449                         /* Move items from the old list node to the replacement node. */
450                         ast_variable_move(new_var, v);
451
452                         /* Replace the old node in the list with the new node. */
453                         new_var->next = v->next;
454                         if (cat->last == v) {
455                                 cat->last = new_var;
456                         }
457                         *prev = new_var;
458
459                         ast_variable_destroy(v);
460
461                         v = new_var;
462                 }
463         }
464 }
465
466 struct ast_config_include *ast_include_find(struct ast_config *conf, const char *included_file)
467 {
468         struct ast_config_include *x;
469         for (x=conf->includes;x;x=x->next) {
470                 if (strcmp(x->included_file,included_file) == 0)
471                         return x;
472         }
473         return 0;
474 }
475
476
477 void ast_variable_append(struct ast_category *category, struct ast_variable *variable)
478 {
479         if (!variable)
480                 return;
481         if (category->last)
482                 category->last->next = variable;
483         else
484                 category->root = variable;
485         category->last = variable;
486         while (category->last->next)
487                 category->last = category->last->next;
488 }
489
490 void ast_variable_insert(struct ast_category *category, struct ast_variable *variable, const char *line)
491 {
492         struct ast_variable *cur = category->root;
493         int lineno;
494         int insertline;
495
496         if (!variable || sscanf(line, "%30d", &insertline) != 1) {
497                 return;
498         }
499         if (!insertline) {
500                 variable->next = category->root;
501                 category->root = variable;
502         } else {
503                 for (lineno = 1; lineno < insertline; lineno++) {
504                         cur = cur->next;
505                         if (!cur->next) {
506                                 break;
507                         }
508                 }
509                 variable->next = cur->next;
510                 cur->next = variable;
511         }
512 }
513
514 static void ast_comment_destroy(struct ast_comment **comment)
515 {
516         struct ast_comment *n, *p;
517
518         for (p = *comment; p; p = n) {
519                 n = p->next;
520                 ast_free(p);
521         }
522
523         *comment = NULL;
524 }
525
526 static void ast_variable_destroy(struct ast_variable *doomed)
527 {
528         ast_comment_destroy(&doomed->precomments);
529         ast_comment_destroy(&doomed->sameline);
530         ast_comment_destroy(&doomed->trailing);
531         ast_free(doomed);
532 }
533
534 struct ast_variable *ast_variables_dup(struct ast_variable *var)
535 {
536         struct ast_variable *cloned;
537         struct ast_variable *tmp;
538
539         if (!(cloned = ast_variable_new(var->name, var->value, var->file))) {
540                 return NULL;
541         }
542
543         tmp = cloned;
544
545         while ((var = var->next)) {
546                 if (!(tmp->next = ast_variable_new(var->name, var->value, var->file))) {
547                         ast_variables_destroy(cloned);
548                         return NULL;
549                 }
550                 tmp = tmp->next;
551         }
552
553         return cloned;
554 }
555
556 void ast_variables_destroy(struct ast_variable *v)
557 {
558         struct ast_variable *vn;
559
560         while (v) {
561                 vn = v;
562                 v = v->next;
563                 ast_variable_destroy(vn);
564         }
565 }
566
567 struct ast_variable *ast_variable_browse(const struct ast_config *config, const char *category)
568 {
569         struct ast_category *cat = NULL;
570
571         if (!category) {
572                 return NULL;
573         }
574
575         if (config->last_browse && (config->last_browse->name == category)) {
576                 cat = config->last_browse;
577         } else {
578                 cat = ast_category_get(config, category);
579         }
580
581         return (cat) ? cat->root : NULL;
582 }
583
584 const char *ast_config_option(struct ast_config *cfg, const char *cat, const char *var)
585 {
586         const char *tmp;
587         tmp = ast_variable_retrieve(cfg, cat, var);
588         if (!tmp) {
589                 tmp = ast_variable_retrieve(cfg, "general", var);
590         }
591         return tmp;
592 }
593
594
595 const char *ast_variable_retrieve(const struct ast_config *config, const char *category, const char *variable)
596 {
597         struct ast_variable *v;
598
599         if (category) {
600                 for (v = ast_variable_browse(config, category); v; v = v->next) {
601                         if (!strcasecmp(variable, v->name)) {
602                                 return v->value;
603                         }
604                 }
605         } else {
606                 struct ast_category *cat;
607
608                 for (cat = config->root; cat; cat = cat->next) {
609                         for (v = cat->root; v; v = v->next) {
610                                 if (!strcasecmp(variable, v->name)) {
611                                         return v->value;
612                                 }
613                         }
614                 }
615         }
616
617         return NULL;
618 }
619
620 static struct ast_variable *variable_clone(const struct ast_variable *old)
621 {
622         struct ast_variable *new = ast_variable_new(old->name, old->value, old->file);
623
624         if (new) {
625                 new->lineno = old->lineno;
626                 new->object = old->object;
627                 new->blanklines = old->blanklines;
628                 /* TODO: clone comments? */
629         }
630
631         return new;
632 }
633
634 static void move_variables(struct ast_category *old, struct ast_category *new)
635 {
636         struct ast_variable *var = old->root;
637
638         old->root = NULL;
639         /* we can just move the entire list in a single op */
640         ast_variable_append(new, var);
641 }
642
643 struct ast_category *ast_category_new(const char *name, const char *in_file, int lineno)
644 {
645         struct ast_category *category;
646
647         category = ast_calloc(1, sizeof(*category));
648         if (!category) {
649                 return NULL;
650         }
651         category->file = ast_strdup(in_file);
652         if (!category->file) {
653                 ast_category_destroy(category);
654                 return NULL;
655         }
656         ast_copy_string(category->name, name, sizeof(category->name));
657         category->lineno = lineno; /* if you don't know the lineno, set it to 999999 or something real big */
658         return category;
659 }
660
661 static struct ast_category *category_get(const struct ast_config *config, const char *category_name, int ignored)
662 {
663         struct ast_category *cat;
664
665         /* try exact match first, then case-insensitive match */
666         for (cat = config->root; cat; cat = cat->next) {
667                 if (cat->name == category_name && (ignored || !cat->ignored))
668                         return cat;
669         }
670
671         for (cat = config->root; cat; cat = cat->next) {
672                 if (!strcasecmp(cat->name, category_name) && (ignored || !cat->ignored))
673                         return cat;
674         }
675
676         return NULL;
677 }
678
679 struct ast_category *ast_category_get(const struct ast_config *config, const char *category_name)
680 {
681         return category_get(config, category_name, 0);
682 }
683
684 int ast_category_exist(const struct ast_config *config, const char *category_name)
685 {
686         return !!ast_category_get(config, category_name);
687 }
688
689 void ast_category_append(struct ast_config *config, struct ast_category *category)
690 {
691         if (config->last)
692                 config->last->next = category;
693         else
694                 config->root = category;
695         category->include_level = config->include_level;
696         config->last = category;
697         config->current = category;
698 }
699
700 void ast_category_insert(struct ast_config *config, struct ast_category *cat, const char *match)
701 {
702         struct ast_category *cur_category;
703
704         if (!cat || !match)
705                 return;
706         if (!strcasecmp(config->root->name, match)) {
707                 cat->next = config->root;
708                 config->root = cat;
709                 return;
710         }
711         for (cur_category = config->root; cur_category; cur_category = cur_category->next) {
712                 if (!strcasecmp(cur_category->next->name, match)) {
713                         cat->next = cur_category->next;
714                         cur_category->next = cat;
715                         break;
716                 }
717         }
718 }
719
720 static void ast_destroy_template_list(struct ast_category *cat)
721 {
722         struct ast_category_template_instance *x;
723
724         while ((x = AST_LIST_REMOVE_HEAD(&cat->template_instances, next)))
725                 ast_free(x);
726 }
727
728 void ast_category_destroy(struct ast_category *cat)
729 {
730         ast_variables_destroy(cat->root);
731         cat->root = NULL;
732         cat->last = NULL;
733         ast_comment_destroy(&cat->precomments);
734         ast_comment_destroy(&cat->sameline);
735         ast_comment_destroy(&cat->trailing);
736         ast_destroy_template_list(cat);
737         ast_free(cat->file);
738         ast_free(cat);
739 }
740
741 static void ast_includes_destroy(struct ast_config_include *incls)
742 {
743         struct ast_config_include *incl,*inclnext;
744
745         for (incl=incls; incl; incl = inclnext) {
746                 inclnext = incl->next;
747                 ast_free(incl->include_location_file);
748                 ast_free(incl->exec_file);
749                 ast_free(incl->included_file);
750                 ast_free(incl);
751         }
752 }
753
754 static struct ast_category *next_available_category(struct ast_category *cat)
755 {
756         for (; cat && cat->ignored; cat = cat->next);
757
758         return cat;
759 }
760
761 /*! return the first var of a category */
762 struct ast_variable *ast_category_first(struct ast_category *cat)
763 {
764         return (cat) ? cat->root : NULL;
765 }
766
767 struct ast_variable *ast_category_root(struct ast_config *config, char *cat)
768 {
769         struct ast_category *category = ast_category_get(config, cat);
770
771         if (category)
772                 return category->root;
773         return NULL;
774 }
775
776 void ast_config_sort_categories(struct ast_config *config, int descending,
777                                                                 int (*comparator)(struct ast_category *p, struct ast_category *q))
778 {
779         /*
780          * The contents of this function are adapted from
781          * an example of linked list merge sorting
782          * copyright 2001 Simon Tatham.
783          *
784          * Permission is hereby granted, free of charge, to any person
785          * obtaining a copy of this software and associated documentation
786          * files (the "Software"), to deal in the Software without
787          * restriction, including without limitation the rights to use,
788          * copy, modify, merge, publish, distribute, sublicense, and/or
789          * sell copies of the Software, and to permit persons to whom the
790          * Software is furnished to do so, subject to the following
791          * conditions:
792          *
793          * The above copyright notice and this permission notice shall be
794          * included in all copies or substantial portions of the Software.
795          *
796          * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
797          * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
798          * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
799          * NONINFRINGEMENT.  IN NO EVENT SHALL SIMON TATHAM BE LIABLE FOR
800          * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
801          * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
802          * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
803          * SOFTWARE.
804          */
805
806         int insize = 1;
807         struct ast_category *p, *q, *e, *tail;
808         int nmerges, psize, qsize, i;
809
810         /* If the descending flag was sent, we'll apply inversion to the comparison function's return. */
811         if (descending) {
812                 descending = -1;
813         } else {
814                 descending = 1;
815         }
816
817         if (!config->root) {
818                 return;
819         }
820
821         while (1) {
822                 p = config->root;
823                 config->root = NULL;
824                 tail = NULL;
825
826                 nmerges = 0; /* count number of merges we do in this pass */
827
828                 while (p) {
829                         nmerges++; /* there exists a merge to be done */
830
831                         /* step `insize' places along from p */
832                         q = p;
833                         psize = 0;
834                         for (i = 0; i < insize; i++) {
835                                 psize++;
836                                 q = q->next;
837                                 if (!q) {
838                                         break;
839                                 }
840                         }
841
842                         /* if q hasn't fallen off end, we have two lists to merge */
843                         qsize = insize;
844
845                         /* now we have two lists; merge them */
846                         while (psize > 0 || (qsize > 0 && q)) {
847                                 /* decide whether next element of merge comes from p or q */
848                                 if (psize == 0) {
849                                         /* p is empty; e must come from q. */
850                                         e = q;
851                                         q = q->next;
852                                         qsize--;
853                                 } else if (qsize == 0 || !q) {
854                                         /* q is empty; e must come from p. */
855                                         e = p; p = p->next; psize--;
856                                 } else if ((comparator(p,q) * descending) <= 0) {
857                                         /* First element of p is lower (or same) e must come from p. */
858                                         e = p;
859                                         p = p->next;
860                                         psize--;
861                                 } else {
862                                         /* First element of q is lower; e must come from q. */
863                                         e = q;
864                                         q = q->next;
865                                         qsize--;
866                                 }
867
868                                 /* add the next element to the merged list */
869                                 if (tail) {
870                                         tail->next = e;
871                                 } else {
872                                         config->root = e;
873                                 }
874                                 tail = e;
875                         }
876
877                         /* now p has stepped `insize' places along, and q has too */
878                         p = q;
879                 }
880
881                 tail->next = NULL;
882
883                 /* If we have done only one merge, we're finished. */
884                 if (nmerges <= 1) { /* allow for nmerges==0, the empty list case */
885                         return;
886                 }
887
888                 /* Otherwise repeat, merging lists twice the size */
889                 insize *= 2;
890         }
891
892 }
893
894 char *ast_category_browse(struct ast_config *config, const char *prev)
895 {
896         struct ast_category *cat;
897
898         if (!prev) {
899                 /* First time browse. */
900                 cat = config->root;
901         } else if (config->last_browse && (config->last_browse->name == prev)) {
902                 /* Simple last browse found. */
903                 cat = config->last_browse->next;
904         } else {
905                 /*
906                  * Config changed since last browse.
907                  *
908                  * First try cheap last browse search. (Rebrowsing a different
909                  * previous category?)
910                  */
911                 for (cat = config->root; cat; cat = cat->next) {
912                         if (cat->name == prev) {
913                                 /* Found it. */
914                                 cat = cat->next;
915                                 break;
916                         }
917                 }
918                 if (!cat) {
919                         /*
920                          * Have to do it the hard way. (Last category was deleted and
921                          * re-added?)
922                          */
923                         for (cat = config->root; cat; cat = cat->next) {
924                                 if (!strcasecmp(cat->name, prev)) {
925                                         /* Found it. */
926                                         cat = cat->next;
927                                         break;
928                                 }
929                         }
930                 }
931         }
932
933         if (cat)
934                 cat = next_available_category(cat);
935
936         config->last_browse = cat;
937         return (cat) ? cat->name : NULL;
938 }
939
940 struct ast_variable *ast_category_detach_variables(struct ast_category *cat)
941 {
942         struct ast_variable *v;
943
944         v = cat->root;
945         cat->root = NULL;
946         cat->last = NULL;
947
948         return v;
949 }
950
951 void ast_category_rename(struct ast_category *cat, const char *name)
952 {
953         ast_copy_string(cat->name, name, sizeof(cat->name));
954 }
955
956 static void inherit_category(struct ast_category *new, const struct ast_category *base)
957 {
958         struct ast_variable *var;
959         struct ast_category_template_instance *x;
960
961         x = ast_calloc(1, sizeof(*x));
962         if (!x) {
963                 return;
964         }
965         strcpy(x->name, base->name);
966         x->inst = base;
967         AST_LIST_INSERT_TAIL(&new->template_instances, x, next);
968         for (var = base->root; var; var = var->next)
969                 ast_variable_append(new, variable_clone(var));
970 }
971
972 struct ast_config *ast_config_new(void)
973 {
974         struct ast_config *config;
975
976         if ((config = ast_calloc(1, sizeof(*config))))
977                 config->max_include_level = MAX_INCLUDE_LEVEL;
978         return config;
979 }
980
981 int ast_variable_delete(struct ast_category *category, const char *variable, const char *match, const char *line)
982 {
983         struct ast_variable *cur, *prev=NULL, *curn;
984         int res = -1;
985         int num_item = 0;
986         int req_item;
987
988         req_item = -1;
989         if (!ast_strlen_zero(line)) {
990                 /* Requesting to delete by item number. */
991                 if (sscanf(line, "%30d", &req_item) != 1
992                         || req_item < 0) {
993                         /* Invalid item number to delete. */
994                         return -1;
995                 }
996         }
997
998         prev = NULL;
999         cur = category->root;
1000         while (cur) {
1001                 curn = cur->next;
1002                 /* Delete by item number or by variable name with optional value. */
1003                 if ((0 <= req_item && num_item == req_item)
1004                         || (req_item < 0 && !strcasecmp(cur->name, variable)
1005                                 && (ast_strlen_zero(match) || !strcasecmp(cur->value, match)))) {
1006                         if (prev) {
1007                                 prev->next = cur->next;
1008                                 if (cur == category->last)
1009                                         category->last = prev;
1010                         } else {
1011                                 category->root = cur->next;
1012                                 if (cur == category->last)
1013                                         category->last = NULL;
1014                         }
1015                         ast_variable_destroy(cur);
1016                         res = 0;
1017                 } else
1018                         prev = cur;
1019
1020                 cur = curn;
1021                 ++num_item;
1022         }
1023         return res;
1024 }
1025
1026 int ast_variable_update(struct ast_category *category, const char *variable,
1027                                                 const char *value, const char *match, unsigned int object)
1028 {
1029         struct ast_variable *cur, *prev=NULL, *newer=NULL;
1030
1031         for (cur = category->root; cur; prev = cur, cur = cur->next) {
1032                 if (strcasecmp(cur->name, variable) ||
1033                         (!ast_strlen_zero(match) && strcasecmp(cur->value, match)))
1034                         continue;
1035
1036                 if (!(newer = ast_variable_new(variable, value, cur->file)))
1037                         return -1;
1038
1039                 ast_variable_move(newer, cur);
1040                 newer->object = newer->object || object;
1041
1042                 /* Replace the old node in the list with the new node. */
1043                 newer->next = cur->next;
1044                 if (prev)
1045                         prev->next = newer;
1046                 else
1047                         category->root = newer;
1048                 if (category->last == cur)
1049                         category->last = newer;
1050
1051                 ast_variable_destroy(cur);
1052
1053                 return 0;
1054         }
1055
1056         /* Could not find variable to update */
1057         return -1;
1058 }
1059
1060 int ast_category_delete(struct ast_config *cfg, const char *category)
1061 {
1062         struct ast_category *prev=NULL, *cat;
1063
1064         cat = cfg->root;
1065         while (cat) {
1066                 if (cat->name == category) {
1067                         if (prev) {
1068                                 prev->next = cat->next;
1069                                 if (cat == cfg->last)
1070                                         cfg->last = prev;
1071                         } else {
1072                                 cfg->root = cat->next;
1073                                 if (cat == cfg->last)
1074                                         cfg->last = NULL;
1075                         }
1076                         ast_category_destroy(cat);
1077                         return 0;
1078                 }
1079                 prev = cat;
1080                 cat = cat->next;
1081         }
1082
1083         prev = NULL;
1084         cat = cfg->root;
1085         while (cat) {
1086                 if (!strcasecmp(cat->name, category)) {
1087                         if (prev) {
1088                                 prev->next = cat->next;
1089                                 if (cat == cfg->last)
1090                                         cfg->last = prev;
1091                         } else {
1092                                 cfg->root = cat->next;
1093                                 if (cat == cfg->last)
1094                                         cfg->last = NULL;
1095                         }
1096                         ast_category_destroy(cat);
1097                         return 0;
1098                 }
1099                 prev = cat;
1100                 cat = cat->next;
1101         }
1102         return -1;
1103 }
1104
1105 int ast_category_empty(struct ast_config *cfg, const char *category)
1106 {
1107         struct ast_category *cat;
1108
1109         for (cat = cfg->root; cat; cat = cat->next) {
1110                 if (!strcasecmp(cat->name, category))
1111                         continue;
1112                 ast_variables_destroy(cat->root);
1113                 cat->root = NULL;
1114                 cat->last = NULL;
1115                 return 0;
1116         }
1117
1118         return -1;
1119 }
1120
1121 void ast_config_destroy(struct ast_config *cfg)
1122 {
1123         struct ast_category *cat, *catn;
1124
1125         if (!cfg)
1126                 return;
1127
1128         ast_includes_destroy(cfg->includes);
1129
1130         cat = cfg->root;
1131         while (cat) {
1132                 catn = cat;
1133                 cat = cat->next;
1134                 ast_category_destroy(catn);
1135         }
1136         ast_free(cfg);
1137 }
1138
1139 struct ast_category *ast_config_get_current_category(const struct ast_config *cfg)
1140 {
1141         return cfg->current;
1142 }
1143
1144 void ast_config_set_current_category(struct ast_config *cfg, const struct ast_category *cat)
1145 {
1146         /* cast below is just to silence compiler warning about dropping "const" */
1147         cfg->current = (struct ast_category *) cat;
1148 }
1149
1150 /*!
1151  * \internal
1152  * \brief Create a new cfmtime list node.
1153  *
1154  * \param filename Config filename caching.
1155  * \param who_asked Who wanted to know.
1156  *
1157  * \retval cfmtime New node on success.
1158  * \retval NULL on error.
1159  */
1160 static struct cache_file_mtime *cfmtime_new(const char *filename, const char *who_asked)
1161 {
1162         struct cache_file_mtime *cfmtime;
1163         char *dst;
1164
1165         cfmtime = ast_calloc(1,
1166                 sizeof(*cfmtime) + strlen(filename) + 1 + strlen(who_asked) + 1);
1167         if (!cfmtime) {
1168                 return NULL;
1169         }
1170         dst = cfmtime->filename;        /* writable space starts here */
1171         strcpy(dst, filename);
1172         dst += strlen(dst) + 1;
1173         cfmtime->who_asked = strcpy(dst, who_asked);
1174
1175         return cfmtime;
1176 }
1177
1178 enum config_cache_attribute_enum {
1179         ATTRIBUTE_INCLUDE = 0,
1180         ATTRIBUTE_EXEC = 1,
1181 };
1182
1183 static void config_cache_attribute(const char *configfile, enum config_cache_attribute_enum attrtype, const char *filename, const char *who_asked)
1184 {
1185         struct cache_file_mtime *cfmtime;
1186         struct cache_file_include *cfinclude;
1187         struct stat statbuf = { 0, };
1188
1189         /* Find our cached entry for this configuration file */
1190         AST_LIST_LOCK(&cfmtime_head);
1191         AST_LIST_TRAVERSE(&cfmtime_head, cfmtime, list) {
1192                 if (!strcmp(cfmtime->filename, configfile) && !strcmp(cfmtime->who_asked, who_asked))
1193                         break;
1194         }
1195         if (!cfmtime) {
1196                 cfmtime = cfmtime_new(configfile, who_asked);
1197                 if (!cfmtime) {
1198                         AST_LIST_UNLOCK(&cfmtime_head);
1199                         return;
1200                 }
1201                 /* Note that the file mtime is initialized to 0, i.e. 1970 */
1202                 AST_LIST_INSERT_SORTALPHA(&cfmtime_head, cfmtime, list, filename);
1203         }
1204
1205         if (!stat(configfile, &statbuf))
1206                 cfmtime->mtime = 0;
1207         else
1208                 cfmtime->mtime = statbuf.st_mtime;
1209
1210         switch (attrtype) {
1211         case ATTRIBUTE_INCLUDE:
1212                 AST_LIST_TRAVERSE(&cfmtime->includes, cfinclude, list) {
1213                         if (!strcmp(cfinclude->include, filename)) {
1214                                 AST_LIST_UNLOCK(&cfmtime_head);
1215                                 return;
1216                         }
1217                 }
1218                 cfinclude = ast_calloc(1, sizeof(*cfinclude) + strlen(filename) + 1);
1219                 if (!cfinclude) {
1220                         AST_LIST_UNLOCK(&cfmtime_head);
1221                         return;
1222                 }
1223                 strcpy(cfinclude->include, filename);
1224                 AST_LIST_INSERT_TAIL(&cfmtime->includes, cfinclude, list);
1225                 break;
1226         case ATTRIBUTE_EXEC:
1227                 cfmtime->has_exec = 1;
1228                 break;
1229         }
1230         AST_LIST_UNLOCK(&cfmtime_head);
1231 }
1232
1233 /*! \brief parse one line in the configuration.
1234  * \verbatim
1235  * We can have a category header        [foo](...)
1236  * a directive                          #include / #exec
1237  * or a regular line                    name = value
1238  * \endverbatim
1239  */
1240 static int process_text_line(struct ast_config *cfg, struct ast_category **cat,
1241         char *buf, int lineno, const char *configfile, struct ast_flags flags,
1242         struct ast_str *comment_buffer,
1243         struct ast_str *lline_buffer,
1244         const char *suggested_include_file,
1245         struct ast_category **last_cat, struct ast_variable **last_var, const char *who_asked)
1246 {
1247         char *c;
1248         char *cur = buf;
1249         struct ast_variable *v;
1250         char cmd[512], exec_file[512];
1251
1252         /* Actually parse the entry */
1253         if (cur[0] == '[') { /* A category header */
1254                 /* format is one of the following:
1255                  * [foo]        define a new category named 'foo'
1256                  * [foo](!)     define a new template category named 'foo'
1257                  * [foo](+)     append to category 'foo', error if foo does not exist.
1258                  * [foo](a)     define a new category and inherit from category or template a.
1259                  *              You can put a comma-separated list of categories and templates
1260                  *              and '!' and '+' between parentheses, with obvious meaning.
1261                  */
1262                 struct ast_category *newcat = NULL;
1263                 char *catname;
1264
1265                 c = strchr(cur, ']');
1266                 if (!c) {
1267                         ast_log(LOG_WARNING, "parse error: no closing ']', line %d of %s\n", lineno, configfile);
1268                         return -1;
1269                 }
1270                 *c++ = '\0';
1271                 cur++;
1272                 if (*c++ != '(')
1273                         c = NULL;
1274                 catname = cur;
1275                 if (!(*cat = newcat = ast_category_new(catname,
1276                                 S_OR(suggested_include_file, cfg->include_level == 1 ? "" : configfile),
1277                                 lineno))) {
1278                         return -1;
1279                 }
1280                 (*cat)->lineno = lineno;
1281                 *last_var = 0;
1282                 *last_cat = newcat;
1283
1284                 /* add comments */
1285                 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS))
1286                         newcat->precomments = ALLOC_COMMENT(comment_buffer);
1287                 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS))
1288                         newcat->sameline = ALLOC_COMMENT(lline_buffer);
1289                 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS))
1290                         CB_RESET(comment_buffer, lline_buffer);
1291
1292                 /* If there are options or categories to inherit from, process them now */
1293                 if (c) {
1294                         if (!(cur = strchr(c, ')'))) {
1295                                 ast_log(LOG_WARNING, "parse error: no closing ')', line %d of %s\n", lineno, configfile);
1296                                 return -1;
1297                         }
1298                         *cur = '\0';
1299                         while ((cur = strsep(&c, ","))) {
1300                                 if (!strcasecmp(cur, "!")) {
1301                                         (*cat)->ignored = 1;
1302                                 } else if (!strcasecmp(cur, "+")) {
1303                                         *cat = category_get(cfg, catname, 1);
1304                                         if (!(*cat)) {
1305                                                 if (newcat)
1306                                                         ast_category_destroy(newcat);
1307                                                 ast_log(LOG_WARNING, "Category addition requested, but category '%s' does not exist, line %d of %s\n", catname, lineno, configfile);
1308                                                 return -1;
1309                                         }
1310                                         if (newcat) {
1311                                                 move_variables(newcat, *cat);
1312                                                 ast_category_destroy(newcat);
1313                                                 newcat = NULL;
1314                                         }
1315                                 } else {
1316                                         struct ast_category *base;
1317
1318                                         base = category_get(cfg, cur, 1);
1319                                         if (!base) {
1320                                                 ast_log(LOG_WARNING, "Inheritance requested, but category '%s' does not exist, line %d of %s\n", cur, lineno, configfile);
1321                                                 return -1;
1322                                         }
1323                                         inherit_category(*cat, base);
1324                                 }
1325                         }
1326                 }
1327                 if (newcat)
1328                         ast_category_append(cfg, *cat);
1329         } else if (cur[0] == '#') { /* A directive - #include or #exec */
1330                 char *cur2;
1331                 char real_inclusion_name[256];
1332                 int do_include = 0;     /* otherwise, it is exec */
1333                 int try_include = 0;
1334
1335                 cur++;
1336                 c = cur;
1337                 while (*c && (*c > 32)) {
1338                         c++;
1339                 }
1340
1341                 if (*c) {
1342                         *c = '\0';
1343                         /* Find real argument */
1344                         c = ast_strip(c + 1);
1345                         if (!(*c)) {
1346                                 c = NULL;
1347                         }
1348                 } else {
1349                         c = NULL;
1350                 }
1351                 if (!strcasecmp(cur, "include")) {
1352                         do_include = 1;
1353                 } else if (!strcasecmp(cur, "tryinclude")) {
1354                         do_include = 1;
1355                         try_include = 1;
1356                 } else if (!strcasecmp(cur, "exec")) {
1357                         if (!ast_opt_exec_includes) {
1358                                 ast_log(LOG_WARNING, "Cannot perform #exec unless execincludes option is enabled in asterisk.conf (options section)!\n");
1359                                 return 0;       /* XXX is this correct ? or we should return -1 ? */
1360                         }
1361                 } else {
1362                         ast_log(LOG_WARNING, "Unknown directive '#%s' at line %d of %s\n", cur, lineno, configfile);
1363                         return 0;       /* XXX is this correct ? or we should return -1 ? */
1364                 }
1365
1366                 if (c == NULL) {
1367                         ast_log(LOG_WARNING, "Directive '#%s' needs an argument (%s) at line %d of %s\n",
1368                                         do_include ? "include / tryinclude" : "exec",
1369                                         do_include ? "filename" : "/path/to/executable",
1370                                         lineno,
1371                                         configfile);
1372                         return 0;       /* XXX is this correct ? or we should return -1 ? */
1373                 }
1374
1375                 cur = c;
1376                 /* Strip off leading and trailing "'s and <>'s */
1377                 /* Dequote */
1378                 if ((*c == '"') || (*c == '<')) {
1379                         char quote_char = *c;
1380                         if (quote_char == '<') {
1381                                 quote_char = '>';
1382                         }
1383
1384                         if (*(c + strlen(c) - 1) == quote_char) {
1385                                 cur++;
1386                                 *(c + strlen(c) - 1) = '\0';
1387                         }
1388                 }
1389                 cur2 = cur;
1390
1391                 /* #exec </path/to/executable>
1392                    We create a tmp file, then we #include it, then we delete it. */
1393                 if (!do_include) {
1394                         struct timeval now = ast_tvnow();
1395                         if (!ast_test_flag(&flags, CONFIG_FLAG_NOCACHE))
1396                                 config_cache_attribute(configfile, ATTRIBUTE_EXEC, NULL, who_asked);
1397                         snprintf(exec_file, sizeof(exec_file), "/var/tmp/exec.%d%d.%ld", (int)now.tv_sec, (int)now.tv_usec, (long)pthread_self());
1398                         snprintf(cmd, sizeof(cmd), "%s > %s 2>&1", cur, exec_file);
1399                         ast_safe_system(cmd);
1400                         cur = exec_file;
1401                 } else {
1402                         if (!ast_test_flag(&flags, CONFIG_FLAG_NOCACHE))
1403                                 config_cache_attribute(configfile, ATTRIBUTE_INCLUDE, cur, who_asked);
1404                         exec_file[0] = '\0';
1405                 }
1406                 /* A #include */
1407                 /* record this inclusion */
1408                 ast_include_new(cfg, cfg->include_level == 1 ? "" : configfile, cur, !do_include, cur2, lineno, real_inclusion_name, sizeof(real_inclusion_name));
1409
1410                 do_include = ast_config_internal_load(cur, cfg, flags, real_inclusion_name, who_asked) ? 1 : 0;
1411                 if (!ast_strlen_zero(exec_file))
1412                         unlink(exec_file);
1413                 if (!do_include && !try_include) {
1414                         ast_log(LOG_ERROR, "The file '%s' was listed as a #include but it does not exist.\n", cur);
1415                         return -1;
1416                 }
1417                 /* XXX otherwise what ? the default return is 0 anyways */
1418
1419         } else {
1420                 /* Just a line (variable = value) */
1421                 int object = 0;
1422                 if (!(*cat)) {
1423                         ast_log(LOG_WARNING,
1424                                 "parse error: No category context for line %d of %s\n", lineno, configfile);
1425                         return -1;
1426                 }
1427                 c = strchr(cur, '=');
1428
1429                 if (c && c > cur && (*(c - 1) == '+')) {
1430                         struct ast_variable *var, *replace = NULL;
1431                         struct ast_str **str = ast_threadstorage_get(&appendbuf, sizeof(*str));
1432
1433                         if (!str || !*str) {
1434                                 return -1;
1435                         }
1436
1437                         *(c - 1) = '\0';
1438                         c++;
1439                         cur = ast_strip(cur);
1440
1441                         /* Must iterate through category until we find last variable of same name (since there could be multiple) */
1442                         for (var = ast_category_first(*cat); var; var = var->next) {
1443                                 if (!strcmp(var->name, cur)) {
1444                                         replace = var;
1445                                 }
1446                         }
1447
1448                         if (!replace) {
1449                                 /* Nothing to replace; just set a variable normally. */
1450                                 goto set_new_variable;
1451                         }
1452
1453                         ast_str_set(str, 0, "%s", replace->value);
1454                         ast_str_append(str, 0, "%s", c);
1455                         ast_str_trim_blanks(*str);
1456                         ast_variable_update(*cat, replace->name, ast_skip_blanks(ast_str_buffer(*str)), replace->value, object);
1457                 } else if (c) {
1458                         *c = 0;
1459                         c++;
1460                         /* Ignore > in => */
1461                         if (*c== '>') {
1462                                 object = 1;
1463                                 c++;
1464                         }
1465 set_new_variable:
1466                         if ((v = ast_variable_new(ast_strip(cur), ast_strip(c), S_OR(suggested_include_file, cfg->include_level == 1 ? "" : configfile)))) {
1467                                 v->lineno = lineno;
1468                                 v->object = object;
1469                                 *last_cat = 0;
1470                                 *last_var = v;
1471                                 /* Put and reset comments */
1472                                 v->blanklines = 0;
1473                                 ast_variable_append(*cat, v);
1474                                 /* add comments */
1475                                 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS))
1476                                         v->precomments = ALLOC_COMMENT(comment_buffer);
1477                                 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS))
1478                                         v->sameline = ALLOC_COMMENT(lline_buffer);
1479                                 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS))
1480                                         CB_RESET(comment_buffer, lline_buffer);
1481
1482                         } else {
1483                                 return -1;
1484                         }
1485                 } else {
1486                         ast_log(LOG_WARNING, "No '=' (equal sign) in line %d of %s\n", lineno, configfile);
1487                 }
1488         }
1489         return 0;
1490 }
1491
1492 static struct ast_config *config_text_file_load(const char *database, const char *table, const char *filename, struct ast_config *cfg, struct ast_flags flags, const char *suggested_include_file, const char *who_asked)
1493 {
1494         char fn[256];
1495 #if defined(LOW_MEMORY)
1496         char buf[512];
1497 #else
1498         char buf[8192];
1499 #endif
1500         char *new_buf, *comment_p, *process_buf;
1501         FILE *f;
1502         int lineno=0;
1503         int comment = 0, nest[MAX_NESTED_COMMENTS];
1504         struct ast_category *cat = NULL;
1505         int count = 0;
1506         struct stat statbuf;
1507         struct cache_file_mtime *cfmtime = NULL;
1508         struct cache_file_include *cfinclude;
1509         struct ast_variable *last_var = 0;
1510         struct ast_category *last_cat = 0;
1511         /*! Growable string buffer */
1512         struct ast_str *comment_buffer = NULL;  /*!< this will be a comment collector.*/
1513         struct ast_str *lline_buffer = NULL;    /*!< A buffer for stuff behind the ; */
1514
1515         if (cfg)
1516                 cat = ast_config_get_current_category(cfg);
1517
1518         if (filename[0] == '/') {
1519                 ast_copy_string(fn, filename, sizeof(fn));
1520         } else {
1521                 snprintf(fn, sizeof(fn), "%s/%s", ast_config_AST_CONFIG_DIR, filename);
1522         }
1523
1524         if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS)) {
1525                 comment_buffer = ast_str_create(CB_SIZE);
1526                 if (comment_buffer)
1527                         lline_buffer = ast_str_create(CB_SIZE);
1528                 if (!lline_buffer) {
1529                         ast_free(comment_buffer);
1530                         ast_log(LOG_ERROR, "Failed to initialize the comment buffer!\n");
1531                         return NULL;
1532                 }
1533         }
1534 #ifdef AST_INCLUDE_GLOB
1535         {
1536                 int glob_ret;
1537                 glob_t globbuf;
1538                 globbuf.gl_offs = 0;    /* initialize it to silence gcc */
1539                 glob_ret = glob(fn, MY_GLOB_FLAGS, NULL, &globbuf);
1540                 if (glob_ret == GLOB_NOSPACE)
1541                         ast_log(LOG_WARNING,
1542                                 "Glob Expansion of pattern '%s' failed: Not enough memory\n", fn);
1543                 else if (glob_ret  == GLOB_ABORTED)
1544                         ast_log(LOG_WARNING,
1545                                 "Glob Expansion of pattern '%s' failed: Read error\n", fn);
1546                 else  {
1547                         /* loop over expanded files */
1548                         int i;
1549                         for (i=0; i<globbuf.gl_pathc; i++) {
1550                                 ast_copy_string(fn, globbuf.gl_pathv[i], sizeof(fn));
1551 #endif
1552         /*
1553          * The following is not a loop, but just a convenient way to define a block
1554          * (using do { } while(0) ), and be able to exit from it with 'continue'
1555          * or 'break' in case of errors. Nice trick.
1556          */
1557         do {
1558                 if (stat(fn, &statbuf))
1559                         continue;
1560
1561                 if (!S_ISREG(statbuf.st_mode)) {
1562                         ast_log(LOG_WARNING, "'%s' is not a regular file, ignoring\n", fn);
1563                         continue;
1564                 }
1565
1566                 if (!ast_test_flag(&flags, CONFIG_FLAG_NOCACHE)) {
1567                         /* Find our cached entry for this configuration file */
1568                         AST_LIST_LOCK(&cfmtime_head);
1569                         AST_LIST_TRAVERSE(&cfmtime_head, cfmtime, list) {
1570                                 if (!strcmp(cfmtime->filename, fn) && !strcmp(cfmtime->who_asked, who_asked))
1571                                         break;
1572                         }
1573                         if (!cfmtime) {
1574                                 cfmtime = cfmtime_new(fn, who_asked);
1575                                 if (!cfmtime)
1576                                         continue;
1577                                 /* Note that the file mtime is initialized to 0, i.e. 1970 */
1578                                 AST_LIST_INSERT_SORTALPHA(&cfmtime_head, cfmtime, list, filename);
1579                         }
1580                 }
1581
1582                 if (cfmtime && (!cfmtime->has_exec) && (cfmtime->mtime == statbuf.st_mtime) && ast_test_flag(&flags, CONFIG_FLAG_FILEUNCHANGED)) {
1583                         /* File is unchanged, what about the (cached) includes (if any)? */
1584                         int unchanged = 1;
1585                         AST_LIST_TRAVERSE(&cfmtime->includes, cfinclude, list) {
1586                                 /* We must glob here, because if we did not, then adding a file to globbed directory would
1587                                  * incorrectly cause no reload to be necessary. */
1588                                 char fn2[256];
1589 #ifdef AST_INCLUDE_GLOB
1590                                 int glob_return;
1591                                 glob_t glob_buf = { .gl_offs = 0 };
1592                                 glob_return = glob(cfinclude->include, MY_GLOB_FLAGS, NULL, &glob_buf);
1593                                 /* On error, we reparse */
1594                                 if (glob_return == GLOB_NOSPACE || glob_return  == GLOB_ABORTED)
1595                                         unchanged = 0;
1596                                 else  {
1597                                         /* loop over expanded files */
1598                                         int j;
1599                                         for (j = 0; j < glob_buf.gl_pathc; j++) {
1600                                                 ast_copy_string(fn2, glob_buf.gl_pathv[j], sizeof(fn2));
1601 #else
1602                                                 ast_copy_string(fn2, cfinclude->include);
1603 #endif
1604                                                 if (config_text_file_load(NULL, NULL, fn2, NULL, flags, "", who_asked) == NULL) {
1605                                                         /* that second-to-last field needs to be looked at in this case... TODO */
1606                                                         unchanged = 0;
1607                                                         /* One change is enough to short-circuit and reload the whole shebang */
1608                                                         break;
1609                                                 }
1610 #ifdef AST_INCLUDE_GLOB
1611                                         }
1612                                 }
1613 #endif
1614                         }
1615
1616                         if (unchanged) {
1617                                 AST_LIST_UNLOCK(&cfmtime_head);
1618                                 ast_free(comment_buffer);
1619                                 ast_free(lline_buffer);
1620 #ifdef AST_INCLUDE_GLOB
1621                                 globfree(&globbuf);
1622 #endif
1623                                 return CONFIG_STATUS_FILEUNCHANGED;
1624                         }
1625                 }
1626                 if (!ast_test_flag(&flags, CONFIG_FLAG_NOCACHE))
1627                         AST_LIST_UNLOCK(&cfmtime_head);
1628
1629                 /* If cfg is NULL, then we just want an answer */
1630                 if (cfg == NULL) {
1631                         ast_free(comment_buffer);
1632                         ast_free(lline_buffer);
1633 #ifdef AST_INCLUDE_GLOB
1634                                 globfree(&globbuf);
1635 #endif
1636                         return NULL;
1637                 }
1638
1639                 if (cfmtime)
1640                         cfmtime->mtime = statbuf.st_mtime;
1641
1642                 if (!(f = fopen(fn, "r"))) {
1643                         ast_debug(1, "No file to parse: %s\n", fn);
1644                         ast_verb(2, "Parsing '%s': Not found (%s)\n", fn, strerror(errno));
1645                         continue;
1646                 }
1647                 count++;
1648                 /* If we get to this point, then we're loading regardless */
1649                 ast_clear_flag(&flags, CONFIG_FLAG_FILEUNCHANGED);
1650                 ast_debug(1, "Parsing %s\n", fn);
1651                 ast_verb(2, "Parsing '%s': Found\n", fn);
1652                 while (!feof(f)) {
1653                         lineno++;
1654                         if (fgets(buf, sizeof(buf), f)) {
1655                                 /* Skip lines that are too long */
1656                                 if (strlen(buf) == sizeof(buf) - 1 && buf[sizeof(buf) - 1] != '\n') {
1657                                         ast_log(LOG_WARNING, "Line %d too long, skipping. It begins with: %.32s...\n", lineno, buf);
1658                                         while (fgets(buf, sizeof(buf), f)) {
1659                                                 if (strlen(buf) != sizeof(buf) - 1 || buf[sizeof(buf) - 1] == '\n') {
1660                                                         break;
1661                                                 }
1662                                         }
1663                                         continue;
1664                                 }
1665
1666                                 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && lline_buffer && ast_str_strlen(lline_buffer)) {
1667                                         CB_ADD(&comment_buffer, ast_str_buffer(lline_buffer));       /* add the current lline buffer to the comment buffer */
1668                                         ast_str_reset(lline_buffer);        /* erase the lline buffer */
1669                                 }
1670
1671                                 new_buf = buf;
1672                                 if (comment)
1673                                         process_buf = NULL;
1674                                 else
1675                                         process_buf = buf;
1676
1677                                 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && comment_buffer && ast_str_strlen(comment_buffer) && (ast_strlen_zero(buf) || strlen(buf) == strspn(buf," \t\n\r"))) {
1678                                         /* blank line? really? Can we add it to an existing comment and maybe preserve inter- and post- comment spacing? */
1679                                         CB_ADD(&comment_buffer, "\n");       /* add a newline to the comment buffer */
1680                                         continue; /* go get a new line, then */
1681                                 }
1682
1683                                 while ((comment_p = strchr(new_buf, COMMENT_META))) {
1684                                         if ((comment_p > new_buf) && (*(comment_p - 1) == '\\')) {
1685                                                 /* Escaped semicolons aren't comments. */
1686                                                 new_buf = comment_p;
1687                                                 /* write over the \ and bring the null terminator with us */
1688                                                 memmove(comment_p - 1, comment_p, strlen(comment_p) + 1);
1689                                         } else if (comment_p[1] == COMMENT_TAG && comment_p[2] == COMMENT_TAG && (comment_p[3] != '-')) {
1690                                                 /* Meta-Comment start detected ";--" */
1691                                                 if (comment < MAX_NESTED_COMMENTS) {
1692                                                         *comment_p = '\0';
1693                                                         new_buf = comment_p + 3;
1694                                                         comment++;
1695                                                         nest[comment-1] = lineno;
1696                                                 } else {
1697                                                         ast_log(LOG_ERROR, "Maximum nest limit of %d reached.\n", MAX_NESTED_COMMENTS);
1698                                                 }
1699                                         } else if ((comment_p >= new_buf + 2) &&
1700                                                    (*(comment_p - 1) == COMMENT_TAG) &&
1701                                                    (*(comment_p - 2) == COMMENT_TAG)) {
1702                                                 /* Meta-Comment end detected */
1703                                                 comment--;
1704                                                 new_buf = comment_p + 1;
1705                                                 if (!comment) {
1706                                                         /* Back to non-comment now */
1707                                                         if (process_buf) {
1708                                                                 /* Actually have to move what's left over the top, then continue */
1709                                                                 char *oldptr;
1710                                                                 oldptr = process_buf + strlen(process_buf);
1711                                                                 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS)) {
1712                                                                         CB_ADD(&comment_buffer, ";");
1713                                                                         CB_ADD_LEN(&comment_buffer, oldptr+1, new_buf-oldptr-1);
1714                                                                 }
1715
1716                                                                 memmove(oldptr, new_buf, strlen(new_buf) + 1);
1717                                                                 new_buf = oldptr;
1718                                                         } else
1719                                                                 process_buf = new_buf;
1720                                                 }
1721                                         } else {
1722                                                 if (!comment) {
1723                                                         /* If ; is found, and we are not nested in a comment,
1724                                                            we immediately stop all comment processing */
1725                                                         if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS)) {
1726                                                                 CB_ADD(&lline_buffer, comment_p);
1727                                                         }
1728                                                         *comment_p = '\0';
1729                                                         new_buf = comment_p;
1730                                                 } else
1731                                                         new_buf = comment_p + 1;
1732                                         }
1733                                 }
1734                                 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && comment && !process_buf ) {
1735                                         CB_ADD(&comment_buffer, buf);  /* the whole line is a comment, store it */
1736                                 }
1737
1738                                 if (process_buf) {
1739                                         char *buffer = ast_strip(process_buf);
1740                                         if (!ast_strlen_zero(buffer)) {
1741                                                 if (process_text_line(cfg, &cat, buffer, lineno, fn, flags, comment_buffer, lline_buffer, suggested_include_file, &last_cat, &last_var, who_asked)) {
1742                                                         cfg = CONFIG_STATUS_FILEINVALID;
1743                                                         break;
1744                                                 }
1745                                         }
1746                                 }
1747                         }
1748                 }
1749                 /* end of file-- anything in a comment buffer? */
1750                 if (last_cat) {
1751                         if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && comment_buffer && ast_str_strlen(comment_buffer)) {
1752                                 if (lline_buffer && ast_str_strlen(lline_buffer)) {
1753                                         CB_ADD(&comment_buffer, ast_str_buffer(lline_buffer));       /* add the current lline buffer to the comment buffer */
1754                                         ast_str_reset(lline_buffer);        /* erase the lline buffer */
1755                                 }
1756                                 last_cat->trailing = ALLOC_COMMENT(comment_buffer);
1757                         }
1758                 } else if (last_var) {
1759                         if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && comment_buffer && ast_str_strlen(comment_buffer)) {
1760                                 if (lline_buffer && ast_str_strlen(lline_buffer)) {
1761                                         CB_ADD(&comment_buffer, ast_str_buffer(lline_buffer));       /* add the current lline buffer to the comment buffer */
1762                                         ast_str_reset(lline_buffer);        /* erase the lline buffer */
1763                                 }
1764                                 last_var->trailing = ALLOC_COMMENT(comment_buffer);
1765                         }
1766                 } else {
1767                         if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && comment_buffer && ast_str_strlen(comment_buffer)) {
1768                                 ast_debug(1, "Nothing to attach comments to, discarded: %s\n", ast_str_buffer(comment_buffer));
1769                         }
1770                 }
1771                 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS))
1772                         CB_RESET(comment_buffer, lline_buffer);
1773
1774                 fclose(f);
1775         } while (0);
1776         if (comment) {
1777                 ast_log(LOG_WARNING,"Unterminated comment detected beginning on line %d\n", nest[comment - 1]);
1778         }
1779 #ifdef AST_INCLUDE_GLOB
1780                                         if (cfg == NULL || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
1781                                                 break;
1782                                         }
1783                                 }
1784                                 globfree(&globbuf);
1785                         }
1786                 }
1787 #endif
1788
1789         if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS)) {
1790                 ast_free(comment_buffer);
1791                 ast_free(lline_buffer);
1792                 comment_buffer = NULL;
1793                 lline_buffer = NULL;
1794         }
1795
1796         if (count == 0)
1797                 return NULL;
1798
1799         return cfg;
1800 }
1801
1802
1803 /* NOTE: categories and variables each have a file and lineno attribute. On a save operation, these are used to determine
1804    which file and line number to write out to. Thus, an entire hierarchy of config files (via #include statements) can be
1805    recreated. BUT, care must be taken to make sure that every cat and var has the proper file name stored, or you may
1806    be shocked and mystified as to why things are not showing up in the files!
1807
1808    Also, All #include/#exec statements are recorded in the "includes" LL in the ast_config structure. The file name
1809    and line number are stored for each include, plus the name of the file included, so that these statements may be
1810    included in the output files on a file_save operation.
1811
1812    The lineno's are really just for relative placement in the file. There is no attempt to make sure that blank lines
1813    are included to keep the lineno's the same between input and output. The lineno fields are used mainly to determine
1814    the position of the #include and #exec directives. So, blank lines tend to disappear from a read/rewrite operation,
1815    and a header gets added.
1816
1817    vars and category heads are output in the order they are stored in the config file. So, if the software
1818    shuffles these at all, then the placement of #include directives might get a little mixed up, because the
1819    file/lineno data probably won't get changed.
1820
1821 */
1822
1823 static void gen_header(FILE *f1, const char *configfile, const char *fn, const char *generator)
1824 {
1825         char date[256]="";
1826         time_t t;
1827
1828         time(&t);
1829         ast_copy_string(date, ctime(&t), sizeof(date));
1830
1831         fprintf(f1, ";!\n");
1832         fprintf(f1, ";! Automatically generated configuration file\n");
1833         if (strcmp(configfile, fn))
1834                 fprintf(f1, ";! Filename: %s (%s)\n", configfile, fn);
1835         else
1836                 fprintf(f1, ";! Filename: %s\n", configfile);
1837         fprintf(f1, ";! Generator: %s\n", generator);
1838         fprintf(f1, ";! Creation Date: %s", date);
1839         fprintf(f1, ";!\n");
1840 }
1841
1842 static void inclfile_destroy(void *obj)
1843 {
1844         const struct inclfile *o = obj;
1845
1846         ast_free(o->fname);
1847 }
1848
1849
1850 static struct inclfile *set_fn(char *fn, int fn_size, const char *file, const char *configfile, struct ao2_container *fileset)
1851 {
1852         struct inclfile lookup;
1853         struct inclfile *fi;
1854
1855         if (ast_strlen_zero(file)) {
1856                 if (configfile[0] == '/')
1857                         ast_copy_string(fn, configfile, fn_size);
1858                 else
1859                         snprintf(fn, fn_size, "%s/%s", ast_config_AST_CONFIG_DIR, configfile);
1860         } else if (file[0] == '/')
1861                 ast_copy_string(fn, file, fn_size);
1862         else
1863                 snprintf(fn, fn_size, "%s/%s", ast_config_AST_CONFIG_DIR, file);
1864         lookup.fname = fn;
1865         fi = ao2_find(fileset, &lookup, OBJ_POINTER);
1866         if (fi) {
1867                 /* Found existing include file scratch pad. */
1868                 return fi;
1869         }
1870
1871         /* set up a file scratch pad */
1872         fi = ao2_alloc(sizeof(struct inclfile), inclfile_destroy);
1873         if (!fi) {
1874                 /* Scratch pad creation failed. */
1875                 return NULL;
1876         }
1877         fi->fname = ast_strdup(fn);
1878         if (!fi->fname) {
1879                 /* Scratch pad creation failed. */
1880                 ao2_ref(fi, -1);
1881                 return NULL;
1882         }
1883         fi->lineno = 1;
1884
1885         ao2_link(fileset, fi);
1886
1887         return fi;
1888 }
1889
1890 static int count_linefeeds(char *str)
1891 {
1892         int count = 0;
1893
1894         while (*str) {
1895                 if (*str =='\n')
1896                         count++;
1897                 str++;
1898         }
1899         return count;
1900 }
1901
1902 static int count_linefeeds_in_comments(struct ast_comment *x)
1903 {
1904         int count = 0;
1905
1906         while (x) {
1907                 count += count_linefeeds(x->cmt);
1908                 x = x->next;
1909         }
1910         return count;
1911 }
1912
1913 static void insert_leading_blank_lines(FILE *fp, struct inclfile *fi, struct ast_comment *precomments, int lineno)
1914 {
1915         int precomment_lines;
1916         int i;
1917
1918         if (!fi) {
1919                 /* No file scratch pad object so insert no blank lines. */
1920                 return;
1921         }
1922
1923         precomment_lines = count_linefeeds_in_comments(precomments);
1924
1925         /* I don't have to worry about those ;! comments, they are
1926            stored in the precomments, but not printed back out.
1927            I did have to make sure that comments following
1928            the ;! header comments were not also deleted in the process */
1929         if (lineno - precomment_lines - fi->lineno < 0) { /* insertions can mess up the line numbering and produce negative numbers that mess things up */
1930                 return;
1931         } else if (lineno == 0) {
1932                 /* Line replacements also mess things up */
1933                 return;
1934         } else if (lineno - precomment_lines - fi->lineno < 5) {
1935                 /* Only insert less than 5 blank lines; if anything more occurs,
1936                  * it's probably due to context deletion. */
1937                 for (i = fi->lineno; i < lineno - precomment_lines; i++) {
1938                         fprintf(fp, "\n");
1939                 }
1940         } else {
1941                 /* Deletion occurred - insert a single blank line, for separation of
1942                  * contexts. */
1943                 fprintf(fp, "\n");
1944         }
1945
1946         fi->lineno = lineno + 1; /* Advance the file lineno */
1947 }
1948
1949 int config_text_file_save(const char *configfile, const struct ast_config *cfg, const char *generator)
1950 {
1951         return ast_config_text_file_save(configfile, cfg, generator);
1952 }
1953
1954 int ast_config_text_file_save(const char *configfile, const struct ast_config *cfg, const char *generator)
1955 {
1956         FILE *f;
1957         char fn[PATH_MAX];
1958         struct ast_variable *var;
1959         struct ast_category *cat;
1960         struct ast_comment *cmt;
1961         struct ast_config_include *incl;
1962         int blanklines = 0;
1963         struct ao2_container *fileset;
1964         struct inclfile *fi;
1965
1966         fileset = ao2_container_alloc(1023, hash_string, hashtab_compare_strings);
1967         if (!fileset) {
1968                 /* Container creation failed. */
1969                 return -1;
1970         }
1971
1972         /* reset all the output flags, in case this isn't our first time saving this data */
1973         for (incl = cfg->includes; incl; incl = incl->next) {
1974                 incl->output = 0;
1975         }
1976
1977         /* go thru all the inclusions and make sure all the files involved (configfile plus all its inclusions)
1978            are all truncated to zero bytes and have that nice header*/
1979         for (incl = cfg->includes; incl; incl = incl->next) {
1980                 if (!incl->exec) { /* leave the execs alone -- we'll write out the #exec directives, but won't zero out the include files or exec files*/
1981                         /* normally, fn is just set to incl->included_file, prepended with config dir if relative */
1982                         fi = set_fn(fn, sizeof(fn), incl->included_file, configfile, fileset);
1983                         f = fopen(fn, "w");
1984                         if (f) {
1985                                 gen_header(f, configfile, fn, generator);
1986                                 fclose(f); /* this should zero out the file */
1987                         } else {
1988                                 ast_debug(1, "Unable to open for writing: %s\n", fn);
1989                                 ast_verb(2, "Unable to write %s (%s)\n", fn, strerror(errno));
1990                         }
1991                         if (fi) {
1992                                 ao2_ref(fi, -1);
1993                         }
1994                 }
1995         }
1996
1997         /* just set fn to absolute ver of configfile */
1998         fi = set_fn(fn, sizeof(fn), 0, configfile, fileset);
1999         if (
2000 #ifdef __CYGWIN__
2001                 (f = fopen(fn, "w+"))
2002 #else
2003                 (f = fopen(fn, "w"))
2004 #endif
2005                 ) {
2006                 ast_verb(2, "Saving '%s'\n", fn);
2007                 gen_header(f, configfile, fn, generator);
2008                 cat = cfg->root;
2009                 fclose(f);
2010                 if (fi) {
2011                         ao2_ref(fi, -1);
2012                 }
2013
2014                 /* from here out, we open each involved file and concat the stuff we need to add to the end and immediately close... */
2015                 /* since each var, cat, and associated comments can come from any file, we have to be
2016                    mobile, and open each file, print, and close it on an entry-by-entry basis */
2017
2018                 while (cat) {
2019                         fi = set_fn(fn, sizeof(fn), cat->file, configfile, fileset);
2020                         f = fopen(fn, "a");
2021                         if (!f) {
2022                                 ast_debug(1, "Unable to open for writing: %s\n", fn);
2023                                 ast_verb(2, "Unable to write %s (%s)\n", fn, strerror(errno));
2024                                 if (fi) {
2025                                         ao2_ref(fi, -1);
2026                                 }
2027                                 ao2_ref(fileset, -1);
2028                                 return -1;
2029                         }
2030
2031                         /* dump any includes that happen before this category header */
2032                         for (incl=cfg->includes; incl; incl = incl->next) {
2033                                 if (strcmp(incl->include_location_file, cat->file) == 0){
2034                                         if (cat->lineno > incl->include_location_lineno && !incl->output) {
2035                                                 if (incl->exec)
2036                                                         fprintf(f,"#exec \"%s\"\n", incl->exec_file);
2037                                                 else
2038                                                         fprintf(f,"#include \"%s\"\n", incl->included_file);
2039                                                 incl->output = 1;
2040                                         }
2041                                 }
2042                         }
2043
2044                         insert_leading_blank_lines(f, fi, cat->precomments, cat->lineno);
2045                         /* Dump section with any appropriate comment */
2046                         for (cmt = cat->precomments; cmt; cmt=cmt->next) {
2047                                 char *cmtp = cmt->cmt;
2048                                 while (cmtp && *cmtp == ';' && *(cmtp+1) == '!') {
2049                                         char *cmtp2 = strchr(cmtp+1, '\n');
2050                                         if (cmtp2)
2051                                                 cmtp = cmtp2+1;
2052                                         else cmtp = 0;
2053                                 }
2054                                 if (cmtp)
2055                                         fprintf(f,"%s", cmtp);
2056                         }
2057                         fprintf(f, "[%s]", cat->name);
2058                         if (cat->ignored || !AST_LIST_EMPTY(&cat->template_instances)) {
2059                                 fprintf(f, "(");
2060                                 if (cat->ignored) {
2061                                         fprintf(f, "!");
2062                                 }
2063                                 if (cat->ignored && !AST_LIST_EMPTY(&cat->template_instances)) {
2064                                         fprintf(f, ",");
2065                                 }
2066                                 if (!AST_LIST_EMPTY(&cat->template_instances)) {
2067                                         struct ast_category_template_instance *x;
2068                                         AST_LIST_TRAVERSE(&cat->template_instances, x, next) {
2069                                                 fprintf(f,"%s",x->name);
2070                                                 if (x != AST_LIST_LAST(&cat->template_instances))
2071                                                         fprintf(f,",");
2072                                         }
2073                                 }
2074                                 fprintf(f, ")");
2075                         }
2076                         for(cmt = cat->sameline; cmt; cmt=cmt->next)
2077                         {
2078                                 fprintf(f,"%s", cmt->cmt);
2079                         }
2080                         if (!cat->sameline)
2081                                 fprintf(f,"\n");
2082                         for (cmt = cat->trailing; cmt; cmt=cmt->next) {
2083                                 if (cmt->cmt[0] != ';' || cmt->cmt[1] != '!')
2084                                         fprintf(f,"%s", cmt->cmt);
2085                         }
2086                         fclose(f);
2087                         if (fi) {
2088                                 ao2_ref(fi, -1);
2089                         }
2090
2091                         var = cat->root;
2092                         while (var) {
2093                                 struct ast_category_template_instance *x;
2094                                 int found = 0;
2095                                 AST_LIST_TRAVERSE(&cat->template_instances, x, next) {
2096                                         struct ast_variable *v;
2097                                         for (v = x->inst->root; v; v = v->next) {
2098                                                 if (!strcasecmp(var->name, v->name) && !strcmp(var->value, v->value)) {
2099                                                         found = 1;
2100                                                         break;
2101                                                 }
2102                                         }
2103                                         if (found)
2104                                                 break;
2105                                 }
2106                                 if (found) {
2107                                         var = var->next;
2108                                         continue;
2109                                 }
2110                                 fi = set_fn(fn, sizeof(fn), var->file, configfile, fileset);
2111                                 f = fopen(fn, "a");
2112                                 if (!f) {
2113                                         ast_debug(1, "Unable to open for writing: %s\n", fn);
2114                                         ast_verb(2, "Unable to write %s (%s)\n", fn, strerror(errno));
2115                                         if (fi) {
2116                                                 ao2_ref(fi, -1);
2117                                         }
2118                                         ao2_ref(fileset, -1);
2119                                         return -1;
2120                                 }
2121
2122                                 /* dump any includes that happen before this category header */
2123                                 for (incl=cfg->includes; incl; incl = incl->next) {
2124                                         if (strcmp(incl->include_location_file, var->file) == 0){
2125                                                 if (var->lineno > incl->include_location_lineno && !incl->output) {
2126                                                         if (incl->exec)
2127                                                                 fprintf(f,"#exec \"%s\"\n", incl->exec_file);
2128                                                         else
2129                                                                 fprintf(f,"#include \"%s\"\n", incl->included_file);
2130                                                         incl->output = 1;
2131                                                 }
2132                                         }
2133                                 }
2134
2135                                 insert_leading_blank_lines(f, fi, var->precomments, var->lineno);
2136                                 for (cmt = var->precomments; cmt; cmt=cmt->next) {
2137                                         if (cmt->cmt[0] != ';' || cmt->cmt[1] != '!')
2138                                                 fprintf(f,"%s", cmt->cmt);
2139                                 }
2140                                 if (var->sameline)
2141                                         fprintf(f, "%s %s %s  %s", var->name, (var->object ? "=>" : "="), var->value, var->sameline->cmt);
2142                                 else
2143                                         fprintf(f, "%s %s %s\n", var->name, (var->object ? "=>" : "="), var->value);
2144                                 for (cmt = var->trailing; cmt; cmt=cmt->next) {
2145                                         if (cmt->cmt[0] != ';' || cmt->cmt[1] != '!')
2146                                                 fprintf(f,"%s", cmt->cmt);
2147                                 }
2148                                 if (var->blanklines) {
2149                                         blanklines = var->blanklines;
2150                                         while (blanklines--)
2151                                                 fprintf(f, "\n");
2152                                 }
2153
2154                                 fclose(f);
2155                                 if (fi) {
2156                                         ao2_ref(fi, -1);
2157                                 }
2158
2159                                 var = var->next;
2160                         }
2161                         cat = cat->next;
2162                 }
2163                 if (!option_debug) {
2164                         ast_verb(2, "Saving '%s': saved\n", fn);
2165                 }
2166         } else {
2167                 ast_debug(1, "Unable to open for writing: %s\n", fn);
2168                 ast_verb(2, "Unable to write '%s' (%s)\n", fn, strerror(errno));
2169                 if (fi) {
2170                         ao2_ref(fi, -1);
2171                 }
2172                 ao2_ref(fileset, -1);
2173                 return -1;
2174         }
2175
2176         /* Now, for files with trailing #include/#exec statements,
2177            we have to make sure every entry is output */
2178         for (incl=cfg->includes; incl; incl = incl->next) {
2179                 if (!incl->output) {
2180                         /* open the respective file */
2181                         fi = set_fn(fn, sizeof(fn), incl->include_location_file, configfile, fileset);
2182                         f = fopen(fn, "a");
2183                         if (!f) {
2184                                 ast_debug(1, "Unable to open for writing: %s\n", fn);
2185                                 ast_verb(2, "Unable to write %s (%s)\n", fn, strerror(errno));
2186                                 if (fi) {
2187                                         ao2_ref(fi, -1);
2188                                 }
2189                                 ao2_ref(fileset, -1);
2190                                 return -1;
2191                         }
2192
2193                         /* output the respective include */
2194                         if (incl->exec)
2195                                 fprintf(f,"#exec \"%s\"\n", incl->exec_file);
2196                         else
2197                                 fprintf(f,"#include \"%s\"\n", incl->included_file);
2198                         fclose(f);
2199                         incl->output = 1;
2200                         if (fi) {
2201                                 ao2_ref(fi, -1);
2202                         }
2203                 }
2204         }
2205         ao2_ref(fileset, -1); /* this should destroy the hash container */
2206
2207         return 0;
2208 }
2209
2210 static void clear_config_maps(void)
2211 {
2212         struct ast_config_map *map;
2213
2214         SCOPED_MUTEX(lock, &config_lock);
2215
2216         while (config_maps) {
2217                 map = config_maps;
2218                 config_maps = config_maps->next;
2219                 ast_free(map);
2220         }
2221 }
2222
2223 #ifdef TEST_FRAMEWORK
2224 int ast_realtime_append_mapping(const char *name, const char *driver, const char *database, const char *table, int priority)
2225 #else
2226 static int ast_realtime_append_mapping(const char *name, const char *driver, const char *database, const char *table, int priority)
2227 #endif
2228 {
2229         struct ast_config_map *map;
2230         char *dst;
2231         int length;
2232
2233         length = sizeof(*map);
2234         length += strlen(name) + 1;
2235         length += strlen(driver) + 1;
2236         length += strlen(database) + 1;
2237         if (table)
2238                 length += strlen(table) + 1;
2239
2240         if (!(map = ast_calloc(1, length)))
2241                 return -1;
2242
2243         dst = map->stuff;       /* writable space starts here */
2244         map->name = strcpy(dst, name);
2245         dst += strlen(dst) + 1;
2246         map->driver = strcpy(dst, driver);
2247         dst += strlen(dst) + 1;
2248         map->database = strcpy(dst, database);
2249         if (table) {
2250                 dst += strlen(dst) + 1;
2251                 map->table = strcpy(dst, table);
2252         }
2253         map->priority = priority;
2254         map->next = config_maps;
2255         config_maps = map;
2256
2257         ast_verb(2, "Binding %s to %s/%s/%s\n", map->name, map->driver, map->database, map->table ? map->table : map->name);
2258
2259         return 0;
2260 }
2261
2262 int read_config_maps(void)
2263 {
2264         struct ast_config *config, *configtmp;
2265         struct ast_variable *v;
2266         char *driver, *table, *database, *textpri, *stringp, *tmp;
2267         struct ast_flags flags = { CONFIG_FLAG_NOREALTIME };
2268         int pri;
2269
2270         clear_config_maps();
2271
2272         configtmp = ast_config_new();
2273         if (!configtmp) {
2274                 ast_log(LOG_ERROR, "Unable to allocate memory for new config\n");
2275                 return -1;
2276         }
2277         configtmp->max_include_level = 1;
2278         config = ast_config_internal_load(extconfig_conf, configtmp, flags, "", "extconfig");
2279         if (config == CONFIG_STATUS_FILEINVALID) {
2280                 return -1;
2281         } else if (!config) {
2282                 ast_config_destroy(configtmp);
2283                 return 0;
2284         }
2285
2286         for (v = ast_variable_browse(config, "settings"); v; v = v->next) {
2287                 char buf[512];
2288                 ast_copy_string(buf, v->value, sizeof(buf));
2289                 stringp = buf;
2290                 driver = strsep(&stringp, ",");
2291
2292                 if ((tmp = strchr(stringp, '\"')))
2293                         stringp = tmp;
2294
2295                 /* check if the database text starts with a double quote */
2296                 if (*stringp == '"') {
2297                         stringp++;
2298                         database = strsep(&stringp, "\"");
2299                         strsep(&stringp, ",");
2300                 } else {
2301                         /* apparently this text has no quotes */
2302                         database = strsep(&stringp, ",");
2303                 }
2304
2305                 table = strsep(&stringp, ",");
2306                 textpri = strsep(&stringp, ",");
2307                 if (!textpri || !(pri = atoi(textpri))) {
2308                         pri = 1;
2309                 }
2310
2311                 if (!strcmp(v->name, extconfig_conf)) {
2312                         ast_log(LOG_WARNING, "Cannot bind '%s'!\n", extconfig_conf);
2313                         continue;
2314                 }
2315
2316                 if (!strcmp(v->name, "asterisk.conf")) {
2317                         ast_log(LOG_WARNING, "Cannot bind 'asterisk.conf'!\n");
2318                         continue;
2319                 }
2320
2321                 if (!strcmp(v->name, "logger.conf")) {
2322                         ast_log(LOG_WARNING, "Cannot bind 'logger.conf'!\n");
2323                         continue;
2324                 }
2325
2326                 if (!driver || !database)
2327                         continue;
2328                 if (!strcasecmp(v->name, "sipfriends")) {
2329                         ast_log(LOG_WARNING, "The 'sipfriends' table is obsolete, update your config to use sippeers instead.\n");
2330                         ast_realtime_append_mapping("sippeers", driver, database, table ? table : "sipfriends", pri);
2331                 } else if (!strcasecmp(v->name, "iaxfriends")) {
2332                         ast_log(LOG_WARNING, "The 'iaxfriends' table is obsolete, update your config to use iaxusers and iaxpeers, though they can point to the same table.\n");
2333                         ast_realtime_append_mapping("iaxusers", driver, database, table ? table : "iaxfriends", pri);
2334                         ast_realtime_append_mapping("iaxpeers", driver, database, table ? table : "iaxfriends", pri);
2335                 } else
2336                         ast_realtime_append_mapping(v->name, driver, database, table, pri);
2337         }
2338
2339         ast_config_destroy(config);
2340         return 0;
2341 }
2342
2343 int ast_config_engine_register(struct ast_config_engine *new)
2344 {
2345         struct ast_config_engine *ptr;
2346
2347         SCOPED_MUTEX(lock, &config_lock);
2348
2349         if (!config_engine_list) {
2350                 config_engine_list = new;
2351         } else {
2352                 for (ptr = config_engine_list; ptr->next; ptr=ptr->next);
2353                 ptr->next = new;
2354         }
2355
2356         ast_log(LOG_NOTICE,"Registered Config Engine %s\n", new->name);
2357
2358         return 1;
2359 }
2360
2361 int ast_config_engine_deregister(struct ast_config_engine *del)
2362 {
2363         struct ast_config_engine *ptr, *last=NULL;
2364
2365         SCOPED_MUTEX(lock, &config_lock);
2366
2367         for (ptr = config_engine_list; ptr; ptr=ptr->next) {
2368                 if (ptr == del) {
2369                         if (last)
2370                                 last->next = ptr->next;
2371                         else
2372                                 config_engine_list = ptr->next;
2373                         break;
2374                 }
2375                 last = ptr;
2376         }
2377
2378         return 0;
2379 }
2380
2381 int ast_realtime_is_mapping_defined(const char *family)
2382 {
2383         struct ast_config_map *map;
2384         SCOPED_MUTEX(lock, &config_lock);
2385
2386         for (map = config_maps; map; map = map->next) {
2387                 if (!strcasecmp(family, map->name)) {
2388                         return 1;
2389                 }
2390         }
2391
2392         return 0;
2393 }
2394
2395 /*! \brief Find realtime engine for realtime family */
2396 static struct ast_config_engine *find_engine(const char *family, int priority, char *database, int dbsiz, char *table, int tabsiz)
2397 {
2398         struct ast_config_engine *eng, *ret = NULL;
2399         struct ast_config_map *map;
2400
2401         SCOPED_MUTEX(lock, &config_lock);
2402
2403         for (map = config_maps; map; map = map->next) {
2404                 if (!strcasecmp(family, map->name) && (priority == map->priority)) {
2405                         if (database)
2406                                 ast_copy_string(database, map->database, dbsiz);
2407                         if (table)
2408                                 ast_copy_string(table, map->table ? map->table : family, tabsiz);
2409                         break;
2410                 }
2411         }
2412
2413         /* Check if the required driver (engine) exist */
2414         if (map) {
2415                 for (eng = config_engine_list; !ret && eng; eng = eng->next) {
2416                         if (!strcasecmp(eng->name, map->driver))
2417                                 ret = eng;
2418                 }
2419         }
2420
2421         /* if we found a mapping, but the engine is not available, then issue a warning */
2422         if (map && !ret)
2423                 ast_log(LOG_WARNING, "Realtime mapping for '%s' found to engine '%s', but the engine is not available\n", map->name, map->driver);
2424
2425         return ret;
2426 }
2427
2428 static struct ast_config_engine text_file_engine = {
2429         .name = "text",
2430         .load_func = config_text_file_load,
2431 };
2432
2433 struct ast_config *ast_config_copy(const struct ast_config *old)
2434 {
2435         struct ast_config *new_config = ast_config_new();
2436         struct ast_category *cat_iter;
2437
2438         if (!new_config) {
2439                 return NULL;
2440         }
2441
2442         for (cat_iter = old->root; cat_iter; cat_iter = cat_iter->next) {
2443                 struct ast_category *new_cat =
2444                         ast_category_new(cat_iter->name, cat_iter->file, cat_iter->lineno);
2445                 if (!new_cat) {
2446                         goto fail;
2447                 }
2448                 ast_category_append(new_config, new_cat);
2449                 if (cat_iter->root) {
2450                         new_cat->root = ast_variables_dup(cat_iter->root);
2451                         if (!new_cat->root) {
2452                                 goto fail;
2453                         }
2454                         new_cat->last = cat_iter->last;
2455                 }
2456         }
2457
2458         return new_config;
2459
2460 fail:
2461         ast_config_destroy(new_config);
2462         return NULL;
2463 }
2464
2465
2466 struct ast_config *ast_config_internal_load(const char *filename, struct ast_config *cfg, struct ast_flags flags, const char *suggested_include_file, const char *who_asked)
2467 {
2468         char db[256];
2469         char table[256];
2470         struct ast_config_engine *loader = &text_file_engine;
2471         struct ast_config *result;
2472
2473         /* The config file itself bumps include_level by 1 */
2474         if (cfg->max_include_level > 0 && cfg->include_level == cfg->max_include_level + 1) {
2475                 ast_log(LOG_WARNING, "Maximum Include level (%d) exceeded\n", cfg->max_include_level);
2476                 return NULL;
2477         }
2478
2479         cfg->include_level++;
2480
2481         if (!ast_test_flag(&flags, CONFIG_FLAG_NOREALTIME) && config_engine_list) {
2482                 struct ast_config_engine *eng;
2483
2484                 eng = find_engine(filename, 1, db, sizeof(db), table, sizeof(table));
2485
2486
2487                 if (eng && eng->load_func) {
2488                         loader = eng;
2489                 } else {
2490                         eng = find_engine("global", 1, db, sizeof(db), table, sizeof(table));
2491                         if (eng && eng->load_func)
2492                                 loader = eng;
2493                 }
2494         }
2495
2496         result = loader->load_func(db, table, filename, cfg, flags, suggested_include_file, who_asked);
2497
2498         if (result && result != CONFIG_STATUS_FILEINVALID && result != CONFIG_STATUS_FILEUNCHANGED) {
2499                 result->include_level--;
2500                 config_hook_exec(filename, who_asked, result);
2501         } else if (result != CONFIG_STATUS_FILEINVALID) {
2502                 cfg->include_level--;
2503         }
2504
2505         return result;
2506 }
2507
2508 struct ast_config *ast_config_load2(const char *filename, const char *who_asked, struct ast_flags flags)
2509 {
2510         struct ast_config *cfg;
2511         struct ast_config *result;
2512
2513         cfg = ast_config_new();
2514         if (!cfg)
2515                 return NULL;
2516
2517         result = ast_config_internal_load(filename, cfg, flags, "", who_asked);
2518         if (!result || result == CONFIG_STATUS_FILEUNCHANGED || result == CONFIG_STATUS_FILEINVALID)
2519                 ast_config_destroy(cfg);
2520
2521         return result;
2522 }
2523
2524 static struct ast_variable *realtime_arguments_to_fields(va_list ap)
2525 {
2526         struct ast_variable *first, *fields = NULL;
2527         const char *newparam = va_arg(ap, const char *), *newval = va_arg(ap, const char *);
2528
2529         if (!(first = ast_variable_new(newparam, newval, ""))) {
2530                 return NULL;
2531         }
2532
2533         while ((newparam = va_arg(ap, const char *))) {
2534                 struct ast_variable *field;
2535
2536                 newval = va_arg(ap, const char *);
2537                 if (!(field = ast_variable_new(newparam, newval, ""))) {
2538                         ast_variables_destroy(fields);
2539                         ast_variables_destroy(first);
2540                         return NULL;
2541                 }
2542
2543                 field->next = fields;
2544                 fields = field;
2545         }
2546
2547         first->next = fields;
2548         fields = first;
2549
2550         return fields;
2551 }
2552
2553 struct ast_variable *ast_load_realtime_all_fields(const char *family, const struct ast_variable *fields)
2554 {
2555         struct ast_config_engine *eng;
2556         char db[256];
2557         char table[256];
2558         struct ast_variable *res=NULL;
2559         int i;
2560
2561         for (i = 1; ; i++) {
2562                 if ((eng = find_engine(family, i, db, sizeof(db), table, sizeof(table)))) {
2563                         if (eng->realtime_func && (res = eng->realtime_func(db, table, fields))) {
2564                                 return res;
2565                         }
2566                 } else {
2567                         return NULL;
2568                 }
2569         }
2570
2571         return res;
2572 }
2573
2574 struct ast_variable *ast_load_realtime_all(const char *family, ...)
2575 {
2576         RAII_VAR(struct ast_variable *, fields, NULL, ast_variables_destroy);
2577         struct ast_variable *res = NULL;
2578         va_list ap;
2579
2580         va_start(ap, family);
2581         fields = realtime_arguments_to_fields(ap);
2582         va_end(ap);
2583
2584         if (fields) {
2585                 res = ast_load_realtime_all_fields(family, fields);
2586         }
2587
2588         return res;
2589 }
2590
2591 struct ast_variable *ast_load_realtime_fields(const char *family, const struct ast_variable *fields)
2592 {
2593         struct ast_variable *res;
2594         struct ast_variable *cur;
2595         struct ast_variable **prev;
2596
2597         res = ast_load_realtime_all_fields(family, fields);
2598
2599         /* Filter the list. */
2600         prev = &res;
2601         cur = res;
2602         while (cur) {
2603                 if (ast_strlen_zero(cur->value)) {
2604                         /* Eliminate empty entries */
2605                         struct ast_variable *next;
2606
2607                         next = cur->next;
2608                         *prev = next;
2609                         ast_variable_destroy(cur);
2610                         cur = next;
2611                 } else {
2612                         /* Make blank entries empty and keep them. */
2613                         if (cur->value[0] == ' ' && cur->value[1] == '\0') {
2614                                 char *vptr = (char *) cur->value;
2615
2616                                 vptr[0] = '\0';
2617                         }
2618
2619                         prev = &cur->next;
2620                         cur = cur->next;
2621                 }
2622         }
2623         return res;
2624 }
2625
2626 struct ast_variable *ast_load_realtime(const char *family, ...)
2627 {
2628         RAII_VAR(struct ast_variable *, fields, NULL, ast_variables_destroy);
2629         va_list ap;
2630
2631         va_start(ap, family);
2632         fields = realtime_arguments_to_fields(ap);
2633         va_end(ap);
2634
2635         return ast_load_realtime_fields(family, fields);
2636 }
2637
2638 /*! \brief Check if realtime engine is configured for family */
2639 int ast_check_realtime(const char *family)
2640 {
2641         struct ast_config_engine *eng;
2642         if (!ast_realtime_enabled()) {
2643                 return 0;       /* There are no engines at all so fail early */
2644         }
2645
2646         eng = find_engine(family, 1, NULL, 0, NULL, 0);
2647         if (eng)
2648                 return 1;
2649         return 0;
2650 }
2651
2652 /*! \brief Check if there's any realtime engines loaded */
2653 int ast_realtime_enabled(void)
2654 {
2655         return config_maps ? 1 : 0;
2656 }
2657
2658 int ast_realtime_require_field(const char *family, ...)
2659 {
2660         struct ast_config_engine *eng;
2661         char db[256];
2662         char table[256];
2663         va_list ap;
2664         int res = -1, i;
2665
2666         va_start(ap, family);
2667         for (i = 1; ; i++) {
2668                 if ((eng = find_engine(family, i, db, sizeof(db), table, sizeof(table)))) {
2669                         /* If the require succeeds, it returns 0. */
2670                         if (eng->require_func && !(res = eng->require_func(db, table, ap))) {
2671                                 break;
2672                         }
2673                 } else {
2674                         break;
2675                 }
2676         }
2677         va_end(ap);
2678
2679         return res;
2680 }
2681
2682 int ast_unload_realtime(const char *family)
2683 {
2684         struct ast_config_engine *eng;
2685         char db[256];
2686         char table[256];
2687         int res = -1, i;
2688
2689         for (i = 1; ; i++) {
2690                 if ((eng = find_engine(family, i, db, sizeof(db), table, sizeof(table)))) {
2691                         if (eng->unload_func) {
2692                                 /* Do this for ALL engines */
2693                                 res = eng->unload_func(db, table);
2694                         }
2695                 } else {
2696                         break;
2697                 }
2698         }
2699         return res;
2700 }
2701
2702 struct ast_config *ast_load_realtime_multientry_fields(const char *family, const struct ast_variable *fields)
2703 {
2704         struct ast_config_engine *eng;
2705         char db[256];
2706         char table[256];
2707         struct ast_config *res = NULL;
2708         int i;
2709
2710         for (i = 1; ; i++) {
2711                 if ((eng = find_engine(family, i, db, sizeof(db), table, sizeof(table)))) {
2712                         if (eng->realtime_multi_func && (res = eng->realtime_multi_func(db, table, fields))) {
2713                                 /* If we were returned an empty cfg, destroy it and return NULL */
2714                                 if (!res->root) {
2715                                         ast_config_destroy(res);
2716                                         res = NULL;
2717                                 }
2718                                 break;
2719                         }
2720                 } else {
2721                         break;
2722                 }
2723         }
2724
2725         return res;
2726 }
2727
2728 struct ast_config *ast_load_realtime_multientry(const char *family, ...)
2729 {
2730         RAII_VAR(struct ast_variable *, fields, NULL, ast_variables_destroy);
2731         va_list ap;
2732
2733         va_start(ap, family);
2734         fields = realtime_arguments_to_fields(ap);
2735         va_end(ap);
2736
2737         return ast_load_realtime_multientry_fields(family, fields);
2738 }
2739
2740 int ast_update_realtime_fields(const char *family, const char *keyfield, const char *lookup, const struct ast_variable *fields)
2741 {
2742         struct ast_config_engine *eng;
2743         int res = -1, i;
2744         char db[256];
2745         char table[256];
2746
2747         for (i = 1; ; i++) {
2748                 if ((eng = find_engine(family, i, db, sizeof(db), table, sizeof(table)))) {
2749                         /* If the update succeeds, it returns 0. */
2750                         if (eng->update_func && !(res = eng->update_func(db, table, keyfield, lookup, fields))) {
2751                                 break;
2752                         }
2753                 } else {
2754                         break;
2755                 }
2756         }
2757
2758         return res;
2759 }
2760
2761 int ast_update_realtime(const char *family, const char *keyfield, const char *lookup, ...)
2762 {
2763         RAII_VAR(struct ast_variable *, fields, NULL, ast_variables_destroy);
2764         va_list ap;
2765
2766         va_start(ap, lookup);
2767         fields = realtime_arguments_to_fields(ap);
2768         va_end(ap);
2769
2770         return ast_update_realtime_fields(family, keyfield, lookup, fields);
2771 }
2772
2773 int ast_update2_realtime_fields(const char *family, const struct ast_variable *lookup_fields, const struct ast_variable *update_fields)
2774 {
2775         struct ast_config_engine *eng;
2776         int res = -1, i;
2777         char db[256];
2778         char table[256];
2779
2780         for (i = 1; ; i++) {
2781                 if ((eng = find_engine(family, i, db, sizeof(db), table, sizeof(table)))) {
2782                         if (eng->update2_func && !(res = eng->update2_func(db, table, lookup_fields, update_fields))) {
2783                                 break;
2784                         }
2785                 } else {
2786                         break;
2787                 }
2788         }
2789
2790         return res;
2791 }
2792
2793 int ast_update2_realtime(const char *family, ...)
2794 {
2795         RAII_VAR(struct ast_variable *, lookup_fields, NULL, ast_variables_destroy);
2796         RAII_VAR(struct ast_variable *, update_fields, NULL, ast_variables_destroy);
2797         va_list ap;
2798
2799         va_start(ap, family);
2800         lookup_fields = realtime_arguments_to_fields(ap);
2801         update_fields = realtime_arguments_to_fields(ap);
2802         va_end(ap);
2803
2804         return ast_update2_realtime_fields(family, lookup_fields, update_fields);
2805 }
2806
2807 int ast_store_realtime_fields(const char *family, const struct ast_variable *fields)
2808 {
2809         struct ast_config_engine *eng;
2810         int res = -1, i;
2811         char db[256];
2812         char table[256];
2813
2814         for (i = 1; ; i++) {
2815                 if ((eng = find_engine(family, i, db, sizeof(db), table, sizeof(table)))) {
2816                         /* If the store succeeds, it returns 0. */
2817                         if (eng->store_func && !(res = eng->store_func(db, table, fields))) {
2818                                 break;
2819                         }
2820                 } else {
2821                         break;
2822                 }
2823         }
2824
2825         return res;
2826 }
2827
2828 int ast_store_realtime(const char *family, ...)
2829 {
2830         RAII_VAR(struct ast_variable *, fields, NULL, ast_variables_destroy);
2831         va_list ap;
2832
2833         va_start(ap, family);
2834         fields = realtime_arguments_to_fields(ap);
2835         va_end(ap);
2836
2837         return ast_store_realtime_fields(family, fields);
2838 }
2839
2840 int ast_destroy_realtime_fields(const char *family, const char *keyfield, const char *lookup, const struct ast_variable *fields)
2841 {
2842         struct ast_config_engine *eng;
2843         int res = -1, i;
2844         char db[256];
2845         char table[256];
2846
2847         for (i = 1; ; i++) {
2848                 if ((eng = find_engine(family, i, db, sizeof(db), table, sizeof(table)))) {
2849                         if (eng->destroy_func && !(res = eng->destroy_func(db, table, keyfield, lookup, fields))) {
2850                                 break;
2851                         }
2852                 } else {
2853                         break;
2854                 }
2855         }
2856
2857         return res;
2858 }
2859
2860 int ast_destroy_realtime(const char *family, const char *keyfield, const char *lookup, ...)
2861 {
2862         RAII_VAR(struct ast_variable *, fields, NULL, ast_variables_destroy);
2863         va_list ap;
2864
2865         va_start(ap, lookup);
2866         fields = realtime_arguments_to_fields(ap);
2867         va_end(ap);
2868
2869         return ast_destroy_realtime_fields(family, keyfield, lookup, fields);
2870 }
2871
2872 char *ast_realtime_decode_chunk(char *chunk)
2873 {
2874         char *orig = chunk;
2875         for (; *chunk; chunk++) {
2876                 if (*chunk == '^' && strchr("0123456789ABCDEFabcdef", chunk[1]) && strchr("0123456789ABCDEFabcdef", chunk[2])) {
2877                         sscanf(chunk + 1, "%02hhX", chunk);
2878                         memmove(chunk + 1, chunk + 3, strlen(chunk + 3) + 1);
2879                 }
2880         }
2881         return orig;
2882 }
2883
2884 char *ast_realtime_encode_chunk(struct ast_str **dest, ssize_t maxlen, const char *chunk)
2885 {
2886         if (!strchr(chunk, ';') && !strchr(chunk, '^')) {
2887                 ast_str_set(dest, maxlen, "%s", chunk);
2888         } else {
2889                 ast_str_reset(*dest);
2890                 for (; *chunk; chunk++) {
2891                         if (strchr(";^", *chunk)) {
2892                                 ast_str_append(dest, maxlen, "^%02hhX", *chunk);
2893                         } else {
2894                                 ast_str_append(dest, maxlen, "%c", *chunk);
2895                         }
2896                 }
2897         }
2898         return ast_str_buffer(*dest);
2899 }
2900
2901 /*! \brief Helper function to parse arguments
2902  * See documentation in config.h
2903  */
2904 int ast_parse_arg(const char *arg, enum ast_parse_flags flags,
2905         void *p_result, ...)
2906 {
2907         va_list ap;
2908         int error = 0;
2909
2910         va_start(ap, p_result);
2911         switch (flags & PARSE_TYPE) {
2912         case PARSE_INT32:
2913         {
2914                 long int x = 0;
2915                 int32_t *result = p_result;
2916                 int32_t def = result ? *result : 0, high = INT32_MAX, low = INT32_MIN;
2917                 char *endptr = NULL;
2918
2919                 /* optional arguments: default value and/or (low, high) */
2920                 if (flags & PARSE_DEFAULT) {
2921                         def = va_arg(ap, int32_t);
2922                 }
2923                 if (flags & (PARSE_IN_RANGE | PARSE_OUT_RANGE)) {
2924                         low = va_arg(ap, int32_t);
2925                         high = va_arg(ap, int32_t);
2926                 }
2927                 if (ast_strlen_zero(arg)) {
2928                         error = 1;
2929                         goto int32_done;
2930                 }
2931                 errno = 0;
2932                 x = strtol(arg, &endptr, 0);
2933                 if (*endptr || errno || x < INT32_MIN || x > INT32_MAX) {
2934                         /* Parse error, or type out of int32_t bounds */
2935                         error = 1;
2936                         goto int32_done;
2937                 }
2938                 error = (x < low) || (x > high);
2939                 if (flags & PARSE_RANGE_DEFAULTS) {
2940                         if (x < low) {
2941                                 def = low;
2942                         } else if (x > high) {
2943                                 def = high;
2944                         }
2945                 }
2946                 if (flags & PARSE_OUT_RANGE) {
2947                         error = !error;
2948                 }
2949 int32_done:
2950                 if (result) {
2951                         *result  = error ? def : x;
2952                 }
2953
2954                 ast_debug(3, "extract int from [%s] in [%d, %d] gives [%ld](%d)\n",
2955                                 arg, low, high, result ? *result : x, error);
2956                 break;
2957         }
2958
2959         case PARSE_UINT32:
2960         {
2961                 unsigned long int x = 0;
2962                 uint32_t *result = p_result;
2963                 uint32_t def = result ? *result : 0, low = 0, high = UINT32_MAX;
2964                 char *endptr = NULL;
2965
2966                 /* optional argument: first default value, then range */
2967                 if (flags & PARSE_DEFAULT) {
2968                         def = va_arg(ap, uint32_t);
2969                 }
2970                 if (flags & (PARSE_IN_RANGE|PARSE_OUT_RANGE)) {
2971                         /* range requested, update bounds */
2972                         low = va_arg(ap, uint32_t);
2973                         high = va_arg(ap, uint32_t);
2974                 }
2975
2976                 if (ast_strlen_zero(arg)) {
2977                         error = 1;
2978                         goto uint32_done;
2979                 }
2980                 /* strtoul will happilly and silently negate negative numbers */
2981                 arg = ast_skip_blanks(arg);
2982                 if (*arg == '-') {
2983                         error = 1;
2984                         goto uint32_done;
2985                 }
2986                 errno = 0;
2987                 x = strtoul(arg, &endptr, 0);
2988                 if (*endptr || errno || x > UINT32_MAX) {
2989                         error = 1;
2990                         goto uint32_done;
2991                 }
2992                 error = (x < low) || (x > high);
2993                 if (flags & PARSE_RANGE_DEFAULTS) {
2994                         if (x < low) {
2995                                 def = low;
2996                         } else if (x > high) {
2997                                 def = high;
2998                         }
2999                 }
3000                 if (flags & PARSE_OUT_RANGE) {
3001                         error = !error;
3002                 }
3003 uint32_done:
3004                 if (result) {
3005                         *result  = error ? def : x;
3006                 }
3007                 ast_debug(3, "extract uint from [%s] in [%u, %u] gives [%lu](%d)\n",
3008                                 arg, low, high, result ? *result : x, error);
3009                 break;
3010         }
3011
3012         case PARSE_DOUBLE:
3013         {
3014                 double *result = p_result;
3015                 double x = 0, def = result ? *result : 0, low = -HUGE_VAL, high = HUGE_VAL;
3016                 char *endptr = NULL;
3017
3018                 /* optional argument: first default value, then range */
3019                 if (flags & PARSE_DEFAULT) {
3020                         def = va_arg(ap, double);
3021                 }
3022                 if (flags & (PARSE_IN_RANGE | PARSE_OUT_RANGE)) {
3023                         /* range requested, update bounds */
3024                         low = va_arg(ap, double);
3025                         high = va_arg(ap, double);
3026                 }
3027                 if (ast_strlen_zero(arg)) {
3028                         error = 1;
3029                         goto double_done;
3030                 }
3031                 errno = 0;
3032                 x = strtod(arg, &endptr);
3033                 if (*endptr || errno == ERANGE) {
3034                         error = 1;
3035                         goto double_done;
3036                 }
3037                 error = (x < low) || (x > high);
3038                 if (flags & PARSE_OUT_RANGE) {
3039                         error = !error;
3040                 }
3041 double_done:
3042                 if (result) {
3043                         *result = error ? def : x;
3044                 }
3045                 ast_debug(3, "extract double from [%s] in [%f, %f] gives [%f](%d)\n",
3046                                 arg, low, high, result ? *result : x, error);
3047                 break;
3048         }
3049         case PARSE_ADDR:
3050             {
3051                 struct ast_sockaddr *addr = (struct ast_sockaddr *)p_result;
3052
3053                 if (!ast_sockaddr_parse(addr, arg, flags & PARSE_PORT_MASK)) {
3054                         error = 1;
3055                 }
3056
3057                 ast_debug(3, "extract addr from %s gives %s(%d)\n",
3058                           arg, ast_sockaddr_stringify(addr), error);
3059
3060                 break;
3061             }
3062         case PARSE_INADDR:      /* TODO Remove this (use PARSE_ADDR instead). */
3063             {
3064                 char *port, *buf;
3065                 struct sockaddr_in _sa_buf;     /* buffer for the result */
3066                 struct sockaddr_in *sa = p_result ?
3067                         (struct sockaddr_in *)p_result : &_sa_buf;
3068                 /* default is either the supplied value or the result itself */
3069                 struct sockaddr_in *def = (flags & PARSE_DEFAULT) ?
3070                         va_arg(ap, struct sockaddr_in *) : sa;
3071                 struct hostent *hp;
3072                 struct ast_hostent ahp;
3073
3074                 memset(&_sa_buf, '\0', sizeof(_sa_buf)); /* clear buffer */
3075                 /* duplicate the string to strip away the :port */
3076                 port = ast_strdupa(arg);
3077                 buf = strsep(&port, ":");
3078                 sa->sin_family = AF_INET;       /* assign family */
3079                 /*
3080                  * honor the ports flag setting, assign default value
3081                  * in case of errors or field unset.
3082                  */
3083                 flags &= PARSE_PORT_MASK; /* the only flags left to process */
3084                 if (port) {
3085                         if (flags == PARSE_PORT_FORBID) {
3086                                 error = 1;      /* port was forbidden */
3087                                 sa->sin_port = def->sin_port;
3088                         } else if (flags == PARSE_PORT_IGNORE)
3089                                 sa->sin_port = def->sin_port;
3090                         else /* accept or require */
3091                                 sa->sin_port = htons(strtol(port, NULL, 0));
3092                 } else {
3093                         sa->sin_port = def->sin_port;
3094                         if (flags == PARSE_PORT_REQUIRE)
3095                                 error = 1;
3096                 }
3097                 /* Now deal with host part, even if we have errors before. */
3098                 hp = ast_gethostbyname(buf, &ahp);
3099                 if (hp) /* resolved successfully */
3100                         memcpy(&sa->sin_addr, hp->h_addr, sizeof(sa->sin_addr));
3101                 else {
3102                         error = 1;
3103                         sa->sin_addr = def->sin_addr;
3104                 }
3105                 ast_debug(3,
3106                         "extract inaddr from [%s] gives [%s:%d](%d)\n",
3107                         arg, ast_inet_ntoa(sa->sin_addr),
3108                         ntohs(sa->sin_port), error);
3109                 break;
3110             }
3111         }
3112         va_end(ap);
3113         return error;
3114 }
3115
3116 static char *handle_cli_core_show_config_mappings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
3117 {
3118         struct ast_config_engine *eng;
3119         struct ast_config_map *map;
3120
3121         switch (cmd) {
3122         case CLI_INIT:
3123                 e->command = "core show config mappings";
3124                 e->usage =
3125                         "Usage: core show config mappings\n"
3126                         "       Shows the filenames to config engines.\n";
3127                 return NULL;
3128         case CLI_GENERATE:
3129                 return NULL;
3130         }
3131
3132         {
3133                 SCOPED_MUTEX(lock, &config_lock);
3134
3135                 if (!config_engine_list) {
3136                         ast_cli(a->fd, "No config mappings found.\n");
3137                 } else {
3138                         for (eng = config_engine_list; eng; eng = eng->next) {
3139                                 ast_cli(a->fd, "Config Engine: %s\n", eng->name);
3140                                 for (map = config_maps; map; map = map->next) {
3141                                         if (!strcasecmp(map->driver, eng->name)) {
3142                                                 ast_cli(a->fd, "===> %s (db=%s, table=%s)\n", map->name, map->database,
3143                                                                 map->table ? map->table : map->name);
3144                                         }
3145                                 }
3146                         }
3147                 }
3148         }
3149
3150         return CLI_SUCCESS;
3151 }
3152
3153 static char *handle_cli_config_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
3154 {
3155         struct cache_file_mtime *cfmtime;
3156         char *prev = "", *completion_value = NULL;
3157         int wordlen, which = 0;
3158
3159         switch (cmd) {
3160         case CLI_INIT:
3161                 e->command = "config reload";
3162                 e->usage =
3163                         "Usage: config reload <filename.conf>\n"
3164                         "   Reloads all modules that reference <filename.conf>\n";
3165                 return NULL;
3166         case CLI_GENERATE:
3167                 if (a->pos > 2) {
3168                         return NULL;
3169                 }
3170
3171                 wordlen = strlen(a->word);
3172
3173                 AST_LIST_LOCK(&cfmtime_head);
3174                 AST_LIST_TRAVERSE(&cfmtime_head, cfmtime, list) {
3175                         /* Skip duplicates - this only works because the list is sorted by filename */
3176                         if (strcmp(cfmtime->filename, prev) == 0) {
3177                                 continue;
3178                         }
3179
3180                         /* Core configs cannot be reloaded */
3181                         if (ast_strlen_zero(cfmtime->who_asked)) {
3182                                 continue;
3183                         }
3184
3185                         if (++which > a->n && strncmp(cfmtime->filename, a->word, wordlen) == 0) {
3186                                 completion_value = ast_strdup(cfmtime->filename);
3187                                 break;
3188                         }
3189
3190                         /* Otherwise save that we've seen this filename */
3191                         prev = cfmtime->filename;
3192                 }
3193                 AST_LIST_UNLOCK(&cfmtime_head);
3194
3195                 return completion_value;
3196         }
3197
3198         if (a->argc != 3) {
3199                 return CLI_SHOWUSAGE;
3200         }
3201
3202         AST_LIST_LOCK(&cfmtime_head);
3203         AST_LIST_TRAVERSE(&cfmtime_head, cfmtime, list) {
3204                 if (!strcmp(cfmtime->filename, a->argv[2])) {
3205                         char *buf = ast_alloca(strlen("module reload ") + strlen(cfmtime->who_asked) + 1);
3206                         sprintf(buf, "module reload %s", cfmtime->who_asked);
3207                         ast_cli_command(a->fd, buf);
3208                 }
3209         }
3210         AST_LIST_UNLOCK(&cfmtime_head);
3211
3212         return CLI_SUCCESS;
3213 }
3214
3215 static char *handle_cli_config_list(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
3216 {
3217         struct cache_file_mtime *cfmtime;
3218
3219         switch (cmd) {
3220         case CLI_INIT:
3221                 e->command = "config list";
3222                 e->usage =
3223                         "Usage: config list\n"
3224                         "   Show all modules that have loaded a configuration file\n";
3225                 return NULL;
3226         case CLI_GENERATE:
3227                 return NULL;
3228         }
3229
3230         AST_LIST_LOCK(&cfmtime_head);
3231         AST_LIST_TRAVERSE(&cfmtime_head, cfmtime, list) {
3232                 ast_cli(a->fd, "%-20.20s %-50s\n", S_OR(cfmtime->who_asked, "core"), cfmtime->filename);
3233         }
3234         AST_LIST_UNLOCK(&cfmtime_head);
3235
3236         return CLI_SUCCESS;
3237 }
3238
3239 static struct ast_cli_entry cli_config[] = {
3240         AST_CLI_DEFINE(handle_cli_core_show_config_mappings, "Display config mappings (file names to config engines)"),
3241         AST_CLI_DEFINE(handle_cli_config_reload, "Force a reload on modules using a particular configuration file"),
3242         AST_CLI_DEFINE(handle_cli_config_list, "Show all files that have loaded a configuration file"),
3243 };
3244
3245 static void config_shutdown(void)
3246 {
3247         struct cache_file_mtime *cfmtime;
3248
3249         AST_LIST_LOCK(&cfmtime_head);
3250         while ((cfmtime = AST_LIST_REMOVE_HEAD(&cfmtime_head, list))) {
3251                 ast_free(cfmtime);
3252         }
3253         AST_LIST_UNLOCK(&cfmtime_head);
3254
3255         ast_cli_unregister_multiple(cli_config, ARRAY_LEN(cli_config));
3256 }
3257
3258 int register_config_cli(void)
3259 {
3260         ast_cli_register_multiple(cli_config, ARRAY_LEN(cli_config));
3261         ast_register_atexit(config_shutdown);
3262         return 0;
3263 }
3264
3265 struct cfg_hook {
3266         const char *name;
3267         const char *filename;
3268         const char *module;
3269         config_hook_cb hook_cb;
3270 };
3271
3272 static void hook_destroy(void *obj)
3273 {
3274         struct cfg_hook *hook = obj;
3275         ast_free((void *) hook->name);
3276         ast_free((void *) hook->filename);
3277         ast_free((void *) hook->module);
3278 }
3279
3280 static int hook_cmp(void *obj, void *arg, int flags)
3281 {
3282         struct cfg_hook *hook1 = obj;
3283         struct cfg_hook *hook2 = arg;
3284
3285         return !(strcasecmp(hook1->name, hook2->name)) ? CMP_MATCH | CMP_STOP : 0;
3286 }
3287
3288 static int hook_hash(const void *obj, const int flags)
3289 {
3290         const struct cfg_hook *hook = obj;
3291
3292         return ast_str_hash(hook->name);
3293 }
3294
3295 void ast_config_hook_unregister(const char *name)
3296 {
3297         struct cfg_hook tmp;
3298
3299         tmp.name = ast_strdupa(name);
3300
3301         ao2_find(cfg_hooks, &tmp, OBJ_POINTER | OBJ_UNLINK | OBJ_NODATA);
3302 }
3303
3304 static void config_hook_exec(const char *filename, const char *module, struct ast_config *cfg)
3305 {
3306         struct ao2_iterator it;
3307         struct cfg_hook *hook;
3308         if (!(cfg_hooks)) {
3309                 return;
3310         }
3311         it = ao2_iterator_init(cfg_hooks, 0);
3312         while ((hook = ao2_iterator_next(&it))) {
3313                 if (!strcasecmp(hook->filename, filename) &&
3314                                 !strcasecmp(hook->module, module)) {
3315                         struct ast_config *copy = ast_config_copy(cfg);
3316                         hook->hook_cb(copy);
3317                 }
3318                 ao2_ref(hook, -1);
3319         }
3320         ao2_iterator_destroy(&it);
3321 }
3322
3323 int ast_config_hook_register(const char *name,
3324                 const char *filename,
3325                 const char *module,
3326                 enum config_hook_flags flags,
3327                 config_hook_cb hook_cb)
3328 {
3329         struct cfg_hook *hook;
3330         if (!cfg_hooks && !(cfg_hooks = ao2_container_alloc(17, hook_hash, hook_cmp))) {
3331                 return -1;
3332         }
3333
3334         if (!(hook = ao2_alloc(sizeof(*hook), hook_destroy))) {
3335                 return -1;
3336         }
3337
3338         hook->hook_cb = hook_cb;
3339         hook->filename = ast_strdup(filename);
3340         hook->name = ast_strdup(name);
3341         hook->module = ast_strdup(module);
3342
3343         ao2_link(cfg_hooks, hook);
3344         return 0;
3345 }