Wed Apr 6 11:29:45 2011

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

Generated on Wed Apr 6 11:29:45 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7