Thu Apr 28 2011 16:56:47

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: 153365 $")
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 
00138    if (ast_strlen_zero(data)) {
00139       ast_log(LOG_WARNING, "SHARED() requires an argument: SHARED(<var>[,<chan>])\n");
00140       return -1;
00141    }
00142 
00143    AST_STANDARD_APP_ARGS(args, data);
00144 
00145    if (!ast_strlen_zero(args.chan)) {
00146       char *prefix = alloca(strlen(args.chan) + 2);
00147       sprintf(prefix, "%s-", args.chan);
00148       if (!(chan = ast_get_channel_by_name_locked(args.chan)) && !(chan = ast_get_channel_by_name_prefix_locked(prefix, strlen(prefix)))) {
00149          ast_log(LOG_ERROR, "Channel '%s' not found!  Variable '%s' will be blank.\n", args.chan, args.var);
00150          return -1;
00151       }
00152    } else
00153       ast_channel_lock(chan);
00154 
00155    if (!(varstore = ast_channel_datastore_find(chan, &shared_variable_info, NULL))) {
00156       ast_channel_unlock(chan);
00157       return -1;
00158    }
00159 
00160    varshead = varstore->data;
00161    *buf = '\0';
00162 
00163    /* Protected by the channel lock */
00164    AST_LIST_TRAVERSE(varshead, var, entries) {
00165       if (!strcmp(args.var, ast_var_name(var))) {
00166          ast_copy_string(buf, ast_var_value(var), len);
00167          break;
00168       }
00169    }
00170 
00171    ast_channel_unlock(chan);
00172 
00173    return 0;
00174 }
00175 
00176 static int shared_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
00177 {
00178    struct ast_datastore *varstore;
00179    struct varshead *varshead;
00180    struct ast_var_t *var;
00181    AST_DECLARE_APP_ARGS(args,
00182       AST_APP_ARG(var);
00183       AST_APP_ARG(chan);
00184    );
00185 
00186    if (ast_strlen_zero(data)) {
00187       ast_log(LOG_WARNING, "SHARED() requires an argument: SHARED(<var>[,<chan>])\n");
00188       return -1;
00189    }
00190 
00191    AST_STANDARD_APP_ARGS(args, data);
00192 
00193    if (!ast_strlen_zero(args.chan)) {
00194       char *prefix = alloca(strlen(args.chan) + 2);
00195       sprintf(prefix, "%s-", args.chan);
00196       if (!(chan = ast_get_channel_by_name_locked(args.chan)) && !(chan = ast_get_channel_by_name_prefix_locked(prefix, strlen(prefix)))) {
00197          ast_log(LOG_ERROR, "Channel '%s' not found!  Variable '%s' not set to '%s'.\n", args.chan, args.var, value);
00198          return -1;
00199       }
00200    } else
00201       ast_channel_lock(chan);
00202 
00203    if (!(varstore = ast_channel_datastore_find(chan, &shared_variable_info, NULL))) {
00204       if (!(varstore = ast_datastore_alloc(&shared_variable_info, NULL))) {
00205          ast_log(LOG_ERROR, "Unable to allocate new datastore.  Shared variable not set.\n");
00206          ast_channel_unlock(chan);
00207          return -1;
00208       }
00209 
00210       if (!(varshead = ast_calloc(1, sizeof(*varshead)))) {
00211          ast_log(LOG_ERROR, "Unable to allocate variable structure.  Shared variable not set.\n");
00212          ast_datastore_free(varstore);
00213          ast_channel_unlock(chan);
00214          return -1;
00215       }
00216 
00217       varstore->data = varshead;
00218       ast_channel_datastore_add(chan, varstore);
00219    }
00220    varshead = varstore->data;
00221 
00222    /* Protected by the channel lock */
00223    AST_LIST_TRAVERSE(varshead, var, entries) {
00224       /* If there's a previous value, remove it */
00225       if (!strcmp(args.var, ast_var_name(var))) {
00226          AST_LIST_REMOVE(varshead, var, entries);
00227          ast_var_delete(var);
00228          break;
00229       }
00230    }
00231 
00232    var = ast_var_assign(args.var, S_OR(value, ""));
00233    AST_LIST_INSERT_HEAD(varshead, var, entries);
00234    manager_event(EVENT_FLAG_DIALPLAN, "VarSet", 
00235       "Channel: %s\r\n"
00236       "Variable: SHARED(%s)\r\n"
00237       "Value: %s\r\n"
00238       "Uniqueid: %s\r\n", 
00239       chan ? chan->name : "none", args.var, value, 
00240       chan ? chan->uniqueid : "none");
00241 
00242    ast_channel_unlock(chan);
00243 
00244    return 0;
00245 }
00246 
00247 static struct ast_custom_function shared_function = {
00248    .name = "SHARED",
00249    .read = shared_read,
00250    .write = shared_write,
00251 };
00252 
00253 static int unload_module(void)
00254 {
00255    int res = 0;
00256 
00257    res |= ast_custom_function_unregister(&global_function);
00258    res |= ast_custom_function_unregister(&shared_function);
00259 
00260    return res;
00261 }
00262 
00263 static int load_module(void)
00264 {
00265    int res = 0;
00266 
00267    res |= ast_custom_function_register(&global_function);
00268    res |= ast_custom_function_register(&shared_function);
00269 
00270    return res;
00271 }
00272 
00273 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Variable dialplan functions");