Mon Jun 27 16:50:53 2011

Asterisk developer's documentation


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 #include "asterisk.h"
00031 
00032 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 153365 $")
00033 
00034 #include "asterisk/module.h"
00035 #include "asterisk/channel.h"
00036 #include "asterisk/pbx.h"
00037 #include "asterisk/app.h"
00038 
00039 /*** DOCUMENTATION
00040    <function name="AST_CONFIG" language="en_US">
00041       <synopsis>
00042          Retrieve a variable from a configuration file.
00043       </synopsis>
00044       <syntax>
00045          <parameter name="config_file" required="true" />
00046          <parameter name="category" required="true" />
00047          <parameter name="variable_name" required="true" />
00048       </syntax>
00049       <description>
00050          <para>This function reads a variable from an Asterisk configuration file.</para>
00051       </description>
00052    </function>
00053 
00054 ***/
00055 
00056 struct config_item {
00057    AST_RWLIST_ENTRY(config_item) entry;
00058    struct ast_config *cfg;
00059    char filename[0];
00060 };
00061 
00062 static AST_RWLIST_HEAD_STATIC(configs, config_item);
00063 
00064 static int config_function_read(struct ast_channel *chan, const char *cmd, char *data, 
00065    char *buf, size_t len) 
00066 {
00067    struct ast_config *cfg;
00068    struct ast_flags cfg_flags = { CONFIG_FLAG_FILEUNCHANGED };
00069    const char *val;
00070    char *parse;
00071    struct config_item *cur;
00072    AST_DECLARE_APP_ARGS(args,
00073       AST_APP_ARG(filename);
00074       AST_APP_ARG(category);
00075       AST_APP_ARG(variable);
00076       AST_APP_ARG(index);
00077    );
00078 
00079    if (ast_strlen_zero(data)) {
00080       ast_log(LOG_ERROR, "AST_CONFIG() requires an argument\n");
00081       return -1;
00082    }
00083 
00084    parse = ast_strdupa(data);
00085    AST_STANDARD_APP_ARGS(args, parse);
00086 
00087    if (ast_strlen_zero(args.filename)) {
00088       ast_log(LOG_ERROR, "AST_CONFIG() requires a filename\n");
00089       return -1;
00090    }
00091 
00092    if (ast_strlen_zero(args.category)) {
00093       ast_log(LOG_ERROR, "AST_CONFIG() requires a category\n");
00094       return -1;
00095    }
00096    
00097    if (ast_strlen_zero(args.variable)) {
00098       ast_log(LOG_ERROR, "AST_CONFIG() requires a variable\n");
00099       return -1;
00100    }
00101 
00102    if (!(cfg = ast_config_load(args.filename, cfg_flags)) || cfg == CONFIG_STATUS_FILEINVALID) {
00103       return -1;
00104    }
00105 
00106    if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
00107       /* Retrieve cfg from list */
00108       AST_RWLIST_RDLOCK(&configs);
00109       AST_RWLIST_TRAVERSE(&configs, cur, entry) {
00110          if (!strcmp(cur->filename, args.filename)) {
00111             break;
00112          }
00113       }
00114 
00115       if (!cur) {
00116          /* At worst, we might leak an entry while upgrading locks */
00117          AST_RWLIST_UNLOCK(&configs);
00118          AST_RWLIST_WRLOCK(&configs);
00119          if (!(cur = ast_malloc(sizeof(*cur) + strlen(args.filename) + 1))) {
00120             AST_RWLIST_UNLOCK(&configs);
00121             return -1;
00122          }
00123 
00124          strcpy(cur->filename, args.filename);
00125 
00126          ast_clear_flag(&cfg_flags, CONFIG_FLAG_FILEUNCHANGED);
00127          if (!(cfg = ast_config_load(args.filename, cfg_flags)) || cfg == CONFIG_STATUS_FILEINVALID) {
00128             ast_free(cur);
00129             AST_RWLIST_UNLOCK(&configs);
00130             return -1;
00131          }
00132 
00133          cur->cfg = cfg;
00134          AST_RWLIST_INSERT_TAIL(&configs, cur, entry);
00135       }
00136 
00137       cfg = cur->cfg;
00138    } else {
00139       /* Replace cfg in list */
00140       AST_RWLIST_WRLOCK(&configs);
00141       AST_RWLIST_TRAVERSE(&configs, cur, entry) {
00142          if (!strcmp(cur->filename, args.filename)) {
00143             break;
00144          }
00145       }
00146 
00147       if (!cur) {
00148          if (!(cur = ast_malloc(sizeof(*cur) + strlen(args.filename) + 1))) {
00149             AST_RWLIST_UNLOCK(&configs);
00150             return -1;
00151          }
00152 
00153          strcpy(cur->filename, args.filename);
00154          cur->cfg = cfg;
00155 
00156          AST_RWLIST_INSERT_TAIL(&configs, cur, entry);
00157       } else {
00158          ast_config_destroy(cur->cfg);
00159          cur->cfg = cfg;
00160       }
00161    }
00162 
00163    if (!(val = ast_variable_retrieve(cfg, args.category, args.variable))) {
00164       ast_log(LOG_ERROR, "'%s' not found in [%s] of '%s'\n", args.variable, 
00165          args.category, args.filename);
00166       AST_RWLIST_UNLOCK(&configs);
00167       return -1;
00168    }
00169 
00170    ast_copy_string(buf, val, len);
00171 
00172    /* Unlock down here, so there's no chance the struct goes away while we're using it. */
00173    AST_RWLIST_UNLOCK(&configs);
00174 
00175    return 0;
00176 }
00177 
00178 static struct ast_custom_function config_function = {
00179    .name = "AST_CONFIG",
00180    .read = config_function_read,
00181 };
00182 
00183 static int unload_module(void)
00184 {
00185    struct config_item *current;
00186    int res = ast_custom_function_unregister(&config_function);
00187 
00188    AST_RWLIST_WRLOCK(&configs);
00189    while ((current = AST_RWLIST_REMOVE_HEAD(&configs, entry))) {
00190       ast_config_destroy(current->cfg);
00191       ast_free(current);
00192    }
00193    AST_RWLIST_UNLOCK(&configs);
00194 
00195    return res;
00196 }
00197 
00198 static int load_module(void)
00199 {
00200    return ast_custom_function_register(&config_function);
00201 }
00202 
00203 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Asterisk configuration file variable access");

Generated on Mon Jun 27 16:50:53 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7