Merge "res_calendar: Specialized calendars depend on symbols of general calendar."
[asterisk/asterisk.git] / main / config.c
index dad3b66..3fbbacf 100644 (file)
 
 #include "asterisk.h"
 
-ASTERISK_REGISTER_FILE()
-
 #include "asterisk/paths.h"    /* use ast_config_AST_CONFIG_DIR */
 #include "asterisk/network.h"  /* we do some sockaddr manipulation here */
+
+#include <string.h>
+#include <libgen.h>
 #include <time.h>
 #include <sys/stat.h>
 
@@ -280,7 +281,7 @@ struct ast_config_include {
 static void ast_variable_destroy(struct ast_variable *doomed);
 static void ast_includes_destroy(struct ast_config_include *incls);
 
-#ifdef MALLOC_DEBUG
+#ifdef __AST_DEBUG_MALLOC
 struct ast_variable *_ast_variable_new(const char *name, const char *value, const char *filename, const char *file, const char *func, int lineno)
 #else
 struct ast_variable *ast_variable_new(const char *name, const char *value, const char *filename)
@@ -297,7 +298,7 @@ struct ast_variable *ast_variable_new(const char *name, const char *value, const
        }
 
        if (
-#ifdef MALLOC_DEBUG
+#ifdef __AST_DEBUG_MALLOC
                (variable = __ast_calloc(1, fn_len + name_len + val_len + sizeof(*variable), file, lineno, func))
 #else
                (variable = ast_calloc(1, fn_len + name_len + val_len + sizeof(*variable)))
@@ -985,13 +986,15 @@ struct ast_category *ast_category_new_template(const char *name, const char *in_
 }
 
 static struct ast_category *category_get_sep(const struct ast_config *config,
-       const char *category_name, const char *filter, char sep)
+       const char *category_name, const char *filter, char sep, char pointer_match_possible)
 {
        struct ast_category *cat;
 
-       for (cat = config->root; cat; cat = cat->next) {
-               if (cat->name == category_name && does_category_match(cat, category_name, filter, sep)) {
-                       return cat;
+       if (pointer_match_possible) {
+               for (cat = config->root; cat; cat = cat->next) {
+                       if (cat->name == category_name && does_category_match(cat, category_name, filter, sep)) {
+                               return cat;
+                       }
                }
        }
 
@@ -1007,7 +1010,7 @@ static struct ast_category *category_get_sep(const struct ast_config *config,
 struct ast_category *ast_category_get(const struct ast_config *config,
        const char *category_name, const char *filter)
 {
-       return category_get_sep(config, category_name, filter, ',');
+       return category_get_sep(config, category_name, filter, ',', 1);
 }
 
 const char *ast_category_get_name(const struct ast_category *category)
@@ -1791,7 +1794,7 @@ static int process_text_line(struct ast_config *cfg, struct ast_category **cat,
                                        if (cur[1] != ',') {
                                                filter = &cur[1];
                                        }
-                                       *cat = category_get_sep(cfg, catname, filter, '&');
+                                       *cat = category_get_sep(cfg, catname, filter, '&', 0);
                                        if (!(*cat)) {
                                                if (newcat) {
                                                        ast_category_destroy(newcat);
@@ -1809,7 +1812,7 @@ static int process_text_line(struct ast_config *cfg, struct ast_category **cat,
                                } else {
                                        struct ast_category *base;
 
-                                       base = ast_category_get(cfg, cur, "TEMPLATES=include");
+                                       base = category_get_sep(cfg, cur, "TEMPLATES=include", ',', 0);
                                        if (!base) {
                                                if (newcat) {
                                                        ast_category_destroy(newcat);
@@ -2188,7 +2191,6 @@ static struct ast_config *config_text_file_load(const char *database, const char
                                /* If we get to this point, then we're loading regardless */
                                ast_clear_flag(&flags, CONFIG_FLAG_FILEUNCHANGED);
                                ast_debug(1, "Parsing %s\n", fn);
-                               ast_verb(2, "Parsing '%s': Found\n", fn);
                                while (!feof(f)) {
                                        lineno++;
                                        if (fgets(buf, sizeof(buf), f)) {
@@ -2512,6 +2514,25 @@ int ast_config_text_file_save(const char *configfile, const struct ast_config *c
        return ast_config_text_file_save2(configfile, cfg, generator, CONFIG_SAVE_FLAG_PRESERVE_EFFECTIVE_CONTEXT);
 }
 
+static int is_writable(const char *fn)
+{
+       if (access(fn, F_OK)) {
+               char *dn = dirname(ast_strdupa(fn));
+
+               if (access(dn, R_OK | W_OK)) {
+                       ast_log(LOG_ERROR, "Unable to write to directory %s (%s)\n", dn, strerror(errno));
+                       return 0;
+               }
+       } else {
+               if (access(fn, R_OK | W_OK)) {
+                       ast_log(LOG_ERROR, "Unable to write %s (%s)\n", fn, strerror(errno));
+                       return 0;
+               }
+       }
+
+       return 1;
+}
+
 int ast_config_text_file_save2(const char *configfile, const struct ast_config *cfg, const char *generator, uint32_t flags)
 {
        FILE *f;
@@ -2534,20 +2555,20 @@ int ast_config_text_file_save2(const char *configfile, const struct ast_config *
        for (incl = cfg->includes; incl; incl = incl->next) {
                /* reset all the output flags in case this isn't our first time saving this data */
                incl->output = 0;
-               /* now make sure we have write access */
+
                if (!incl->exec) {
+                       /* now make sure we have write access to the include file or its parent directory */
                        make_fn(fn, sizeof(fn), incl->included_file, configfile);
-                       if (access(fn, R_OK | W_OK)) {
-                               ast_log(LOG_ERROR, "Unable to write %s (%s)\n", fn, strerror(errno));
+                       /* If the file itself doesn't exist, make sure we have write access to the directory */
+                       if (!is_writable(fn)) {
                                return -1;
                        }
                }
        }
 
-       /* now make sure we have write access to the main config file */
+       /* now make sure we have write access to the main config file or its parent directory */
        make_fn(fn, sizeof(fn), 0, configfile);
-       if (access(fn, R_OK | W_OK)) {
-               ast_log(LOG_ERROR, "Unable to write %s (%s)\n", fn, strerror(errno));
+       if (!is_writable(fn)) {
                return -1;
        }
 
@@ -3721,6 +3742,55 @@ uint32_done:
                break;
        }
 
+       case PARSE_TIMELEN:
+       {
+               int x = 0;
+               int *result = p_result;
+               int def = result ? *result : 0;
+               int high = INT_MAX;
+               int low = INT_MIN;
+               enum ast_timelen defunit;
+
+               defunit = va_arg(ap, enum ast_timelen);
+               /* optional arguments: default value and/or (low, high) */
+               if (flags & PARSE_DEFAULT) {
+                       def = va_arg(ap, int);
+               }
+               if (flags & (PARSE_IN_RANGE | PARSE_OUT_RANGE)) {
+                       low = va_arg(ap, int);
+                       high = va_arg(ap, int);
+               }
+               if (ast_strlen_zero(arg)) {
+                       error = 1;
+                       goto timelen_done;
+               }
+               error = ast_app_parse_timelen(arg, &x, defunit);
+               if (error || x < INT_MIN || x > INT_MAX) {
+                       /* Parse error, or type out of int bounds */
+                       error = 1;
+                       goto timelen_done;
+               }
+               error = (x < low) || (x > high);
+               if (flags & PARSE_RANGE_DEFAULTS) {
+                       if (x < low) {
+                               def = low;
+                       } else if (x > high) {
+                               def = high;
+                       }
+               }
+               if (flags & PARSE_OUT_RANGE) {
+                       error = !error;
+               }
+timelen_done:
+               if (result) {
+                       *result  = error ? def : x;
+               }
+
+               ast_debug(3, "extract timelen from [%s] in [%d, %d] gives [%d](%d)\n",
+                               arg, low, high, result ? *result : x, error);
+               break;
+       }
+
        case PARSE_DOUBLE:
        {
                double *result = p_result;