func_config.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 2008, Digium, Inc.
00005  *
00006  * Russell Bryant <russell@digium.com>
00007  * Tilghman Lesher <func_config__200803@the-tilghman.com>
00008  *
00009  * See http://www.asterisk.org for more information about
00010  * the Asterisk project. Please do not directly contact
00011  * any of the maintainers of this project for assistance;
00012  * the project provides a web site, mailing lists and IRC
00013  * channels for your use.
00014  *
00015  * This program is free software, distributed under the terms of
00016  * the GNU General Public License Version 2. See the LICENSE file
00017  * at the top of the source tree.
00018  */
00019 
00020 /*! \file
00021  *
00022  * \brief A function to retrieve variables from an Asterisk configuration file
00023  *
00024  * \author Russell Bryant <russell@digium.com>
00025  * \author Tilghman Lesher <func_config__200803@the-tilghman.com>
00026  * 
00027  * \ingroup functions
00028  */
00029 
00030 /*** MODULEINFO
00031    <support_level>core</support_level>
00032  ***/
00033 
00034 #include "asterisk.h"
00035 
00036 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 430316 $")
00037 
00038 #include "asterisk/module.h"
00039 #include "asterisk/channel.h"
00040 #include "asterisk/pbx.h"
00041 #include "asterisk/app.h"
00042 
00043 /*** DOCUMENTATION
00044    <function name="AST_CONFIG" language="en_US">
00045       <synopsis>
00046          Retrieve a variable from a configuration file.
00047       </synopsis>
00048       <syntax>
00049          <parameter name="config_file" required="true" />
00050          <parameter name="category" required="true" />
00051          <parameter name="variable_name" required="true" />
00052          <parameter name="index" required="false">
00053             <para>If there are multiple variables with the same name, you can specify
00054             <literal>0</literal> for the first item (default), <literal>-1</literal> for the last
00055             item, or any other number for that specific item.  <literal>-1</literal> is useful
00056             when the variable is derived from a template and you want the effective value (the last
00057             occurrence), not the value from the template (the first occurrence).</para>
00058          </parameter>
00059       </syntax>
00060       <description>
00061          <para>This function reads a variable from an Asterisk configuration file.</para>
00062       </description>
00063    </function>
00064 
00065 ***/
00066 
00067 struct config_item {
00068    AST_RWLIST_ENTRY(config_item) entry;
00069    struct ast_config *cfg;
00070    char filename[0];
00071 };
00072 
00073 static AST_RWLIST_HEAD_STATIC(configs, config_item);
00074 
00075 static int config_function_read(struct ast_channel *chan, const char *cmd, char *data,
00076    char *buf, size_t len)
00077 {
00078    struct ast_config *cfg;
00079    struct ast_flags cfg_flags = { CONFIG_FLAG_FILEUNCHANGED };
00080    char *parse;
00081    struct config_item *cur;
00082    int index = 0;
00083    struct ast_variable *var;
00084    struct ast_variable *found = NULL;
00085    int ix = 0;
00086    AST_DECLARE_APP_ARGS(args,
00087       AST_APP_ARG(filename);
00088       AST_APP_ARG(category);
00089       AST_APP_ARG(variable);
00090       AST_APP_ARG(index);
00091    );
00092 
00093    if (ast_strlen_zero(data)) {
00094       ast_log(LOG_ERROR, "AST_CONFIG() requires an argument\n");
00095       return -1;
00096    }
00097 
00098    parse = ast_strdupa(data);
00099    AST_STANDARD_APP_ARGS(args, parse);
00100 
00101    if (ast_strlen_zero(args.filename)) {
00102       ast_log(LOG_ERROR, "AST_CONFIG() requires a filename\n");
00103       return -1;
00104    }
00105 
00106    if (ast_strlen_zero(args.category)) {
00107       ast_log(LOG_ERROR, "AST_CONFIG() requires a category\n");
00108       return -1;
00109    }
00110    
00111    if (ast_strlen_zero(args.variable)) {
00112       ast_log(LOG_ERROR, "AST_CONFIG() requires a variable\n");
00113       return -1;
00114    }
00115 
00116    if (!ast_strlen_zero(args.index)) {
00117       if (!sscanf(args.index, "%d", &index)) {
00118          ast_log(LOG_ERROR, "AST_CONFIG() index must be an integer\n");
00119          return -1;
00120       }
00121    }
00122 
00123    if (!(cfg = ast_config_load(args.filename, cfg_flags)) || cfg == CONFIG_STATUS_FILEINVALID) {
00124       return -1;
00125    }
00126 
00127    if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
00128       /* Retrieve cfg from list */
00129       AST_RWLIST_RDLOCK(&configs);
00130       AST_RWLIST_TRAVERSE(&configs, cur, entry) {
00131          if (!strcmp(cur->filename, args.filename)) {
00132             break;
00133          }
00134       }
00135 
00136       if (!cur) {
00137          /* At worst, we might leak an entry while upgrading locks */
00138          AST_RWLIST_UNLOCK(&configs);
00139          AST_RWLIST_WRLOCK(&configs);
00140          if (!(cur = ast_calloc(1, sizeof(*cur) + strlen(args.filename) + 1))) {
00141             AST_RWLIST_UNLOCK(&configs);
00142             return -1;
00143          }
00144 
00145          strcpy(cur->filename, args.filename);
00146 
00147          ast_clear_flag(&cfg_flags, CONFIG_FLAG_FILEUNCHANGED);
00148          if (!(cfg = ast_config_load(args.filename, cfg_flags)) || cfg == CONFIG_STATUS_FILEINVALID) {
00149             ast_free(cur);
00150             AST_RWLIST_UNLOCK(&configs);
00151             return -1;
00152          }
00153 
00154          cur->cfg = cfg;
00155          AST_RWLIST_INSERT_TAIL(&configs, cur, entry);
00156       }
00157 
00158       cfg = cur->cfg;
00159    } else {
00160       /* Replace cfg in list */
00161       AST_RWLIST_WRLOCK(&configs);
00162       AST_RWLIST_TRAVERSE(&configs, cur, entry) {
00163          if (!strcmp(cur->filename, args.filename)) {
00164             break;
00165          }
00166       }
00167 
00168       if (!cur) {
00169          if (!(cur = ast_calloc(1, sizeof(*cur) + strlen(args.filename) + 1))) {
00170             AST_RWLIST_UNLOCK(&configs);
00171             return -1;
00172          }
00173 
00174          strcpy(cur->filename, args.filename);
00175          cur->cfg = cfg;
00176 
00177          AST_RWLIST_INSERT_TAIL(&configs, cur, entry);
00178       } else {
00179          ast_config_destroy(cur->cfg);
00180          cur->cfg = cfg;
00181       }
00182    }
00183 
00184    for (var = ast_category_root(cfg, args.category); var; var = var->next) {
00185       if (strcasecmp(args.variable, var->name)) {
00186          continue;
00187       }
00188       found = var;
00189       if (index == -1) {
00190          continue;
00191       }
00192       if (ix == index) {
00193          break;
00194       }
00195       found = NULL;
00196       ix++;
00197    }
00198 
00199    if (!found) {
00200       ast_debug(1, "'%s' not found at index %d in [%s] of '%s'.  Maximum index found: %d\n",
00201          args.variable, index, args.category, args.filename, ix);
00202       AST_RWLIST_UNLOCK(&configs);
00203       return -1;
00204    }
00205 
00206    ast_copy_string(buf, found->value, len);
00207 
00208    /* Unlock down here, so there's no chance the struct goes away while we're using it. */
00209    AST_RWLIST_UNLOCK(&configs);
00210 
00211    return 0;
00212 }
00213 
00214 static struct ast_custom_function config_function = {
00215    .name = "AST_CONFIG",
00216    .read = config_function_read,
00217 };
00218 
00219 static int unload_module(void)
00220 {
00221    struct config_item *current;
00222    int res = ast_custom_function_unregister(&config_function);
00223 
00224    AST_RWLIST_WRLOCK(&configs);
00225    while ((current = AST_RWLIST_REMOVE_HEAD(&configs, entry))) {
00226       ast_config_destroy(current->cfg);
00227       ast_free(current);
00228    }
00229    AST_RWLIST_UNLOCK(&configs);
00230 
00231    return res;
00232 }
00233 
00234 static int load_module(void)
00235 {
00236    return ast_custom_function_register(&config_function);
00237 }
00238 
00239 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Asterisk configuration file variable access");

Generated on Thu Apr 16 06:27:35 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6