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: 411328 $")
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/stasis_channels.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    <managerEvent language="en_US" name="VarSet">
00087       <managerEventInstance class="EVENT_FLAG_DIALPLAN">
00088          <synopsis>Raised when a variable is shared between channels.</synopsis>
00089          <syntax>
00090             <channel_snapshot/>
00091             <parameter name="Variable">
00092                <para>The SHARED variable being set.</para>
00093                <note><para>The variable name will always be enclosed with
00094                <literal>SHARED()</literal></para></note>
00095             </parameter>
00096             <parameter name="Value">
00097                <para>The new value of the variable.</para>
00098             </parameter>
00099          </syntax>
00100          <see-also>
00101             <ref type="function">SHARED</ref>
00102          </see-also>
00103       </managerEventInstance>
00104    </managerEvent>
00105  ***/
00106 
00107 static void shared_variable_free(void *data);
00108 
00109 static const struct ast_datastore_info shared_variable_info = {
00110    .type = "SHARED_VARIABLES",
00111    .destroy = shared_variable_free,
00112 };
00113 
00114 static void shared_variable_free(void *data)
00115 {
00116    struct varshead *varshead = data;
00117    struct ast_var_t *var;
00118 
00119    while ((var = AST_LIST_REMOVE_HEAD(varshead, entries))) {
00120       ast_var_delete(var);
00121    }
00122    ast_free(varshead);
00123 }
00124 
00125 static int global_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
00126 {
00127    const char *var = pbx_builtin_getvar_helper(NULL, data);
00128 
00129    *buf = '\0';
00130 
00131    if (var)
00132       ast_copy_string(buf, var, len);
00133 
00134    return 0;
00135 }
00136 
00137 static int global_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
00138 {
00139    pbx_builtin_setvar_helper(NULL, data, value);
00140 
00141    return 0;
00142 }
00143 
00144 static struct ast_custom_function global_function = {
00145    .name = "GLOBAL",
00146    .read = global_read,
00147    .write = global_write,
00148 };
00149 
00150 static int shared_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
00151 {
00152    struct ast_datastore *varstore;
00153    struct varshead *varshead;
00154    struct ast_var_t *var;
00155    AST_DECLARE_APP_ARGS(args,
00156       AST_APP_ARG(var);
00157       AST_APP_ARG(chan);
00158    );
00159    struct ast_channel *c_ref = NULL;
00160 
00161    if (ast_strlen_zero(data)) {
00162       ast_log(LOG_WARNING, "SHARED() requires an argument: SHARED(<var>[,<chan>])\n");
00163       return -1;
00164    }
00165 
00166    AST_STANDARD_APP_ARGS(args, data);
00167 
00168    if (!ast_strlen_zero(args.chan)) {
00169       char *prefix = ast_alloca(strlen(args.chan) + 2);
00170       sprintf(prefix, "%s-", args.chan);
00171       if (!(c_ref = ast_channel_get_by_name(args.chan)) && !(c_ref = ast_channel_get_by_name_prefix(prefix, strlen(prefix)))) {
00172          ast_log(LOG_ERROR, "Channel '%s' not found!  Variable '%s' will be blank.\n", args.chan, args.var);
00173          return -1;
00174       }
00175       chan = c_ref;
00176    } else if (!chan) {
00177       ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
00178       return -1;
00179    }
00180 
00181    ast_channel_lock(chan);
00182 
00183    if (!(varstore = ast_channel_datastore_find(chan, &shared_variable_info, NULL))) {
00184       ast_channel_unlock(chan);
00185       if (c_ref) {
00186          c_ref = ast_channel_unref(c_ref);
00187       }
00188       return -1;
00189    }
00190 
00191    varshead = varstore->data;
00192    *buf = '\0';
00193 
00194    /* Protected by the channel lock */
00195    AST_LIST_TRAVERSE(varshead, var, entries) {
00196       if (!strcmp(args.var, ast_var_name(var))) {
00197          ast_copy_string(buf, ast_var_value(var), len);
00198          break;
00199       }
00200    }
00201 
00202    ast_channel_unlock(chan);
00203 
00204    if (c_ref) {
00205       c_ref = ast_channel_unref(c_ref);
00206    }
00207 
00208    return 0;
00209 }
00210 
00211 static int shared_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
00212 {
00213    struct ast_datastore *varstore;
00214    struct varshead *varshead;
00215    struct ast_var_t *var;
00216    AST_DECLARE_APP_ARGS(args,
00217       AST_APP_ARG(var);
00218       AST_APP_ARG(chan);
00219    );
00220    struct ast_channel *c_ref = NULL;
00221    int len;
00222    RAII_VAR(char *, shared_buffer, NULL, ast_free);
00223 
00224    if (ast_strlen_zero(data)) {
00225       ast_log(LOG_WARNING, "SHARED() requires an argument: SHARED(<var>[,<chan>])\n");
00226       return -1;
00227    }
00228 
00229    AST_STANDARD_APP_ARGS(args, data);
00230 
00231    if (!ast_strlen_zero(args.chan)) {
00232       char *prefix = ast_alloca(strlen(args.chan) + 2);
00233       sprintf(prefix, "%s-", args.chan);
00234       if (!(c_ref = ast_channel_get_by_name(args.chan)) && !(c_ref = ast_channel_get_by_name_prefix(prefix, strlen(prefix)))) {
00235          ast_log(LOG_ERROR, "Channel '%s' not found!  Variable '%s' not set to '%s'.\n", args.chan, args.var, value);
00236          return -1;
00237       }
00238       chan = c_ref;
00239    } else if (!chan) {
00240       ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
00241       return -1;
00242    }
00243 
00244    len = 9 + strlen(args.var); /* SHARED() + var */
00245    shared_buffer = ast_malloc(len);
00246    if (!shared_buffer) {
00247       if (c_ref) {
00248          ast_channel_unref(c_ref);
00249       }
00250       return -1;
00251    }
00252 
00253    ast_channel_lock(chan);
00254 
00255    if (!(varstore = ast_channel_datastore_find(chan, &shared_variable_info, NULL))) {
00256       if (!(varstore = ast_datastore_alloc(&shared_variable_info, NULL))) {
00257          ast_log(LOG_ERROR, "Unable to allocate new datastore.  Shared variable not set.\n");
00258          ast_channel_unlock(chan);
00259          if (c_ref) {
00260             c_ref = ast_channel_unref(c_ref);
00261          }
00262          return -1;
00263       }
00264 
00265       if (!(varshead = ast_calloc(1, sizeof(*varshead)))) {
00266          ast_log(LOG_ERROR, "Unable to allocate variable structure.  Shared variable not set.\n");
00267          ast_datastore_free(varstore);
00268          ast_channel_unlock(chan);
00269          if (c_ref) {
00270             c_ref = ast_channel_unref(c_ref);
00271          }
00272          return -1;
00273       }
00274 
00275       varstore->data = varshead;
00276       ast_channel_datastore_add(chan, varstore);
00277    }
00278    varshead = varstore->data;
00279 
00280    /* Protected by the channel lock */
00281    AST_LIST_TRAVERSE_SAFE_BEGIN(varshead, var, entries) {
00282       /* If there's a previous value, remove it */
00283       if (!strcmp(args.var, ast_var_name(var))) {
00284          AST_LIST_REMOVE_CURRENT(entries);
00285          ast_var_delete(var);
00286          break;
00287       }
00288    }
00289    AST_LIST_TRAVERSE_SAFE_END;
00290 
00291    if ((var = ast_var_assign(args.var, S_OR(value, "")))) {
00292       AST_LIST_INSERT_HEAD(varshead, var, entries);
00293 
00294       sprintf(shared_buffer, "SHARED(%s)", args.var);
00295       ast_channel_publish_varset(chan, shared_buffer, value);
00296    }
00297 
00298    ast_channel_unlock(chan);
00299 
00300    if (c_ref) {
00301       c_ref = ast_channel_unref(c_ref);
00302    }
00303 
00304    return 0;
00305 }
00306 
00307 static struct ast_custom_function shared_function = {
00308    .name = "SHARED",
00309    .read = shared_read,
00310    .write = shared_write,
00311 };
00312 
00313 static int unload_module(void)
00314 {
00315    int res = 0;
00316 
00317    res |= ast_custom_function_unregister(&global_function);
00318    res |= ast_custom_function_unregister(&shared_function);
00319 
00320    return res;
00321 }
00322 
00323 static int load_module(void)
00324 {
00325    int res = 0;
00326 
00327    res |= ast_custom_function_register(&global_function);
00328    res |= ast_custom_function_register(&shared_function);
00329 
00330    return res;
00331 }
00332 
00333 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Variable dialplan functions");

Generated on Thu Apr 16 06:27:35 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6