Mon Mar 19 11:30:27 2012

Asterisk developer's documentation


func_global.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 2006, Tilghman Lesher
00005  *
00006  * Tilghman Lesher <func_global__200605@the-tilghman.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*! \file
00020  *
00021  * \brief Global variable dialplan functions
00022  *
00023  * \author Tilghman Lesher <func_global__200605@the-tilghman.com>
00024  *
00025  * \ingroup functions
00026  */
00027 
00028 /*** MODULEINFO
00029    <support_level>core</support_level>
00030  ***/
00031 
00032 #include "asterisk.h"
00033 
00034 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 328209 $")
00035 
00036 #include <sys/stat.h>
00037 
00038 #include "asterisk/module.h"
00039 #include "asterisk/pbx.h"
00040 #include "asterisk/channel.h"
00041 #include "asterisk/app.h"
00042 #include "asterisk/manager.h"
00043 
00044 /*** DOCUMENTATION
00045    <function name="GLOBAL" language="en_US">
00046       <synopsis>
00047          Gets or sets the global variable specified.
00048       </synopsis>
00049       <syntax>
00050          <parameter name="varname" required="true">
00051             <para>Global variable name</para>
00052          </parameter>
00053       </syntax>
00054       <description>
00055          <para>Set or get the value of a global variable specified in <replaceable>varname</replaceable></para>
00056       </description>
00057    </function>
00058    <function name="SHARED" language="en_US">
00059       <synopsis>
00060          Gets or sets the shared variable specified.
00061       </synopsis>
00062       <syntax>
00063          <parameter name="varname" required="true">
00064             <para>Variable name</para>
00065          </parameter>
00066          <parameter name="channel">
00067             <para>If not specified will default to current channel. It is the complete
00068             channel name: <literal>SIP/12-abcd1234</literal> or the prefix only <literal>SIP/12</literal>.</para>
00069          </parameter>
00070       </syntax>
00071       <description>
00072          <para>Implements a shared variable area, in which you may share variables between
00073          channels.</para>
00074          <para>The variables used in this space are separate from the general namespace of
00075          the channel and thus <variable>SHARED(foo)</variable> and <variable>foo</variable> 
00076          represent two completely different variables, despite sharing the same name.</para>
00077          <para>Finally, realize that there is an inherent race between channels operating
00078          at the same time, fiddling with each others' internal variables, which is why
00079          this special variable namespace exists; it is to remind you that variables in
00080          the SHARED namespace may change at any time, without warning.  You should
00081          therefore take special care to ensure that when using the SHARED namespace,
00082          you retrieve the variable and store it in a regular channel variable before
00083          using it in a set of calculations (or you might be surprised by the result).</para>
00084       </description>
00085    </function>
00086 
00087  ***/
00088 
00089 static void shared_variable_free(void *data);
00090 
00091 static struct ast_datastore_info shared_variable_info = {
00092    .type = "SHARED_VARIABLES",
00093    .destroy = shared_variable_free,
00094 };
00095 
00096 static void shared_variable_free(void *data)
00097 {
00098    struct varshead *varshead = data;
00099    struct ast_var_t *var;
00100 
00101    while ((var = AST_LIST_REMOVE_HEAD(varshead, entries))) {
00102       ast_var_delete(var);
00103    }
00104    ast_free(varshead);
00105 }
00106 
00107 static int global_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
00108 {
00109    const char *var = pbx_builtin_getvar_helper(NULL, data);
00110 
00111    *buf = '\0';
00112 
00113    if (var)
00114       ast_copy_string(buf, var, len);
00115 
00116    return 0;
00117 }
00118 
00119 static int global_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
00120 {
00121    pbx_builtin_setvar_helper(NULL, data, value);
00122 
00123    return 0;
00124 }
00125 
00126 static struct ast_custom_function global_function = {
00127    .name = "GLOBAL",
00128    .read = global_read,
00129    .write = global_write,
00130 };
00131 
00132 static int shared_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
00133 {
00134    struct ast_datastore *varstore;
00135    struct varshead *varshead;
00136    struct ast_var_t *var;
00137    AST_DECLARE_APP_ARGS(args,
00138       AST_APP_ARG(var);
00139       AST_APP_ARG(chan);
00140    );
00141    struct ast_channel *c_ref = NULL;
00142 
00143    if (ast_strlen_zero(data)) {
00144       ast_log(LOG_WARNING, "SHARED() requires an argument: SHARED(<var>[,<chan>])\n");
00145       return -1;
00146    }
00147 
00148    AST_STANDARD_APP_ARGS(args, data);
00149 
00150    if (!ast_strlen_zero(args.chan)) {
00151       char *prefix = alloca(strlen(args.chan) + 2);
00152       sprintf(prefix, "%s-", args.chan);
00153       if (!(c_ref = ast_channel_get_by_name(args.chan)) && !(c_ref = ast_channel_get_by_name_prefix(prefix, strlen(prefix)))) {
00154          ast_log(LOG_ERROR, "Channel '%s' not found!  Variable '%s' will be blank.\n", args.chan, args.var);
00155          return -1;
00156       }
00157       chan = c_ref;
00158    }
00159 
00160    ast_channel_lock(chan);
00161 
00162    if (!(varstore = ast_channel_datastore_find(chan, &shared_variable_info, NULL))) {
00163       ast_channel_unlock(chan);
00164       if (c_ref) {
00165          c_ref = ast_channel_unref(c_ref);
00166       }
00167       return -1;
00168    }
00169 
00170    varshead = varstore->data;
00171    *buf = '\0';
00172 
00173    /* Protected by the channel lock */
00174    AST_LIST_TRAVERSE(varshead, var, entries) {
00175       if (!strcmp(args.var, ast_var_name(var))) {
00176          ast_copy_string(buf, ast_var_value(var), len);
00177          break;
00178       }
00179    }
00180 
00181    ast_channel_unlock(chan);
00182 
00183    if (c_ref) {
00184       c_ref = ast_channel_unref(c_ref);
00185    }
00186 
00187    return 0;
00188 }
00189 
00190 static int shared_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
00191 {
00192    struct ast_datastore *varstore;
00193    struct varshead *varshead;
00194    struct ast_var_t *var;
00195    AST_DECLARE_APP_ARGS(args,
00196       AST_APP_ARG(var);
00197       AST_APP_ARG(chan);
00198    );
00199    struct ast_channel *c_ref = NULL;
00200 
00201    if (ast_strlen_zero(data)) {
00202       ast_log(LOG_WARNING, "SHARED() requires an argument: SHARED(<var>[,<chan>])\n");
00203       return -1;
00204    }
00205 
00206    AST_STANDARD_APP_ARGS(args, data);
00207 
00208    if (!ast_strlen_zero(args.chan)) {
00209       char *prefix = alloca(strlen(args.chan) + 2);
00210       sprintf(prefix, "%s-", args.chan);
00211       if (!(c_ref = ast_channel_get_by_name(args.chan)) && !(c_ref = ast_channel_get_by_name_prefix(prefix, strlen(prefix)))) {
00212          ast_log(LOG_ERROR, "Channel '%s' not found!  Variable '%s' not set to '%s'.\n", args.chan, args.var, value);
00213          return -1;
00214       }
00215       chan = c_ref;
00216    }
00217 
00218    ast_channel_lock(chan);
00219 
00220    if (!(varstore = ast_channel_datastore_find(chan, &shared_variable_info, NULL))) {
00221       if (!(varstore = ast_datastore_alloc(&shared_variable_info, NULL))) {
00222          ast_log(LOG_ERROR, "Unable to allocate new datastore.  Shared variable not set.\n");
00223          ast_channel_unlock(chan);
00224          if (c_ref) {
00225             c_ref = ast_channel_unref(c_ref);
00226          }
00227          return -1;
00228       }
00229 
00230       if (!(varshead = ast_calloc(1, sizeof(*varshead)))) {
00231          ast_log(LOG_ERROR, "Unable to allocate variable structure.  Shared variable not set.\n");
00232          ast_datastore_free(varstore);
00233          ast_channel_unlock(chan);
00234          if (c_ref) {
00235             c_ref = ast_channel_unref(c_ref);
00236          }
00237          return -1;
00238       }
00239 
00240       varstore->data = varshead;
00241       ast_channel_datastore_add(chan, varstore);
00242    }
00243    varshead = varstore->data;
00244 
00245    /* Protected by the channel lock */
00246    AST_LIST_TRAVERSE(varshead, var, entries) {
00247       /* If there's a previous value, remove it */
00248       if (!strcmp(args.var, ast_var_name(var))) {
00249          AST_LIST_REMOVE(varshead, var, entries);
00250          ast_var_delete(var);
00251          break;
00252       }
00253    }
00254 
00255    var = ast_var_assign(args.var, S_OR(value, ""));
00256    AST_LIST_INSERT_HEAD(varshead, var, entries);
00257    manager_event(EVENT_FLAG_DIALPLAN, "VarSet", 
00258       "Channel: %s\r\n"
00259       "Variable: SHARED(%s)\r\n"
00260       "Value: %s\r\n"
00261       "Uniqueid: %s\r\n", 
00262       chan ? chan->name : "none", args.var, value, 
00263       chan ? chan->uniqueid : "none");
00264 
00265    ast_channel_unlock(chan);
00266 
00267    if (c_ref) {
00268       c_ref = ast_channel_unref(c_ref);
00269    }
00270 
00271    return 0;
00272 }
00273 
00274 static struct ast_custom_function shared_function = {
00275    .name = "SHARED",
00276    .read = shared_read,
00277    .write = shared_write,
00278 };
00279 
00280 static int unload_module(void)
00281 {
00282    int res = 0;
00283 
00284    res |= ast_custom_function_unregister(&global_function);
00285    res |= ast_custom_function_unregister(&shared_function);
00286 
00287    return res;
00288 }
00289 
00290 static int load_module(void)
00291 {
00292    int res = 0;
00293 
00294    res |= ast_custom_function_register(&global_function);
00295    res |= ast_custom_function_register(&shared_function);
00296 
00297    return res;
00298 }
00299 
00300 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Variable dialplan functions");

Generated on Mon Mar 19 11:30:27 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7