Fri Aug 17 00:17:16 2018

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: 411313 $")
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 const 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 = ast_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    } else if (!chan) {
00159       ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
00160       return -1;
00161    }
00162 
00163    ast_channel_lock(chan);
00164 
00165    if (!(varstore = ast_channel_datastore_find(chan, &shared_variable_info, NULL))) {
00166       ast_channel_unlock(chan);
00167       if (c_ref) {
00168          c_ref = ast_channel_unref(c_ref);
00169       }
00170       return -1;
00171    }
00172 
00173    varshead = varstore->data;
00174    *buf = '\0';
00175 
00176    /* Protected by the channel lock */
00177    AST_LIST_TRAVERSE(varshead, var, entries) {
00178       if (!strcmp(args.var, ast_var_name(var))) {
00179          ast_copy_string(buf, ast_var_value(var), len);
00180          break;
00181       }
00182    }
00183 
00184    ast_channel_unlock(chan);
00185 
00186    if (c_ref) {
00187       c_ref = ast_channel_unref(c_ref);
00188    }
00189 
00190    return 0;
00191 }
00192 
00193 static int shared_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
00194 {
00195    struct ast_datastore *varstore;
00196    struct varshead *varshead;
00197    struct ast_var_t *var;
00198    AST_DECLARE_APP_ARGS(args,
00199       AST_APP_ARG(var);
00200       AST_APP_ARG(chan);
00201    );
00202    struct ast_channel *c_ref = NULL;
00203 
00204    if (ast_strlen_zero(data)) {
00205       ast_log(LOG_WARNING, "SHARED() requires an argument: SHARED(<var>[,<chan>])\n");
00206       return -1;
00207    }
00208 
00209    AST_STANDARD_APP_ARGS(args, data);
00210 
00211    if (!ast_strlen_zero(args.chan)) {
00212       char *prefix = ast_alloca(strlen(args.chan) + 2);
00213       sprintf(prefix, "%s-", args.chan);
00214       if (!(c_ref = ast_channel_get_by_name(args.chan)) && !(c_ref = ast_channel_get_by_name_prefix(prefix, strlen(prefix)))) {
00215          ast_log(LOG_ERROR, "Channel '%s' not found!  Variable '%s' not set to '%s'.\n", args.chan, args.var, value);
00216          return -1;
00217       }
00218       chan = c_ref;
00219    } else if (!chan) {
00220       ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
00221       return -1;
00222    }
00223 
00224    ast_channel_lock(chan);
00225 
00226    if (!(varstore = ast_channel_datastore_find(chan, &shared_variable_info, NULL))) {
00227       if (!(varstore = ast_datastore_alloc(&shared_variable_info, NULL))) {
00228          ast_log(LOG_ERROR, "Unable to allocate new datastore.  Shared variable not set.\n");
00229          ast_channel_unlock(chan);
00230          if (c_ref) {
00231             c_ref = ast_channel_unref(c_ref);
00232          }
00233          return -1;
00234       }
00235 
00236       if (!(varshead = ast_calloc(1, sizeof(*varshead)))) {
00237          ast_log(LOG_ERROR, "Unable to allocate variable structure.  Shared variable not set.\n");
00238          ast_datastore_free(varstore);
00239          ast_channel_unlock(chan);
00240          if (c_ref) {
00241             c_ref = ast_channel_unref(c_ref);
00242          }
00243          return -1;
00244       }
00245 
00246       varstore->data = varshead;
00247       ast_channel_datastore_add(chan, varstore);
00248    }
00249    varshead = varstore->data;
00250 
00251    /* Protected by the channel lock */
00252    AST_LIST_TRAVERSE_SAFE_BEGIN(varshead, var, entries) {
00253       /* If there's a previous value, remove it */
00254       if (!strcmp(args.var, ast_var_name(var))) {
00255          AST_LIST_REMOVE_CURRENT(entries);
00256          ast_var_delete(var);
00257          break;
00258       }
00259    }
00260    AST_LIST_TRAVERSE_SAFE_END;
00261 
00262    if ((var = ast_var_assign(args.var, S_OR(value, "")))) {
00263       AST_LIST_INSERT_HEAD(varshead, var, entries);
00264       manager_event(EVENT_FLAG_DIALPLAN, "VarSet", 
00265          "Channel: %s\r\n"
00266          "Variable: SHARED(%s)\r\n"
00267          "Value: %s\r\n"
00268          "Uniqueid: %s\r\n", 
00269          chan ? chan->name : "none", args.var, value, 
00270          chan ? chan->uniqueid : "none");
00271    }
00272 
00273    ast_channel_unlock(chan);
00274 
00275    if (c_ref) {
00276       c_ref = ast_channel_unref(c_ref);
00277    }
00278 
00279    return 0;
00280 }
00281 
00282 static struct ast_custom_function shared_function = {
00283    .name = "SHARED",
00284    .read = shared_read,
00285    .write = shared_write,
00286 };
00287 
00288 static int unload_module(void)
00289 {
00290    int res = 0;
00291 
00292    res |= ast_custom_function_unregister(&global_function);
00293    res |= ast_custom_function_unregister(&shared_function);
00294 
00295    return res;
00296 }
00297 
00298 static int load_module(void)
00299 {
00300    int res = 0;
00301 
00302    res |= ast_custom_function_register(&global_function);
00303    res |= ast_custom_function_register(&shared_function);
00304 
00305    return res;
00306 }
00307 
00308 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Variable dialplan functions");

Generated on 17 Aug 2018 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1