00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "asterisk.h"
00029
00030 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 106309 $")
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 static void shared_variable_free(void *data);
00041
00042 static struct ast_datastore_info shared_variable_info = {
00043 .type = "SHARED_VARIABLES",
00044 .destroy = shared_variable_free,
00045 };
00046
00047 static void shared_variable_free(void *data)
00048 {
00049 struct varshead *varshead = data;
00050 struct ast_var_t *var;
00051
00052 while ((var = AST_LIST_REMOVE_HEAD(varshead, entries))) {
00053 ast_var_delete(var);
00054 }
00055 ast_free(varshead);
00056 }
00057
00058 static int global_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
00059 {
00060 const char *var = pbx_builtin_getvar_helper(NULL, data);
00061
00062 *buf = '\0';
00063
00064 if (var)
00065 ast_copy_string(buf, var, len);
00066
00067 return 0;
00068 }
00069
00070 static int global_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
00071 {
00072 pbx_builtin_setvar_helper(NULL, data, value);
00073
00074 return 0;
00075 }
00076
00077 static struct ast_custom_function global_function = {
00078 .name = "GLOBAL",
00079 .synopsis = "Gets or sets the global variable specified",
00080 .syntax = "GLOBAL(<varname>)",
00081 .read = global_read,
00082 .write = global_write,
00083 };
00084
00085 static int shared_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
00086 {
00087 struct ast_datastore *varstore;
00088 struct varshead *varshead;
00089 struct ast_var_t *var;
00090 AST_DECLARE_APP_ARGS(args,
00091 AST_APP_ARG(var);
00092 AST_APP_ARG(chan);
00093 );
00094
00095 if (ast_strlen_zero(data)) {
00096 ast_log(LOG_WARNING, "SHARED() requires an argument: SHARED(<var>[,<chan>])\n");
00097 return -1;
00098 }
00099
00100 AST_STANDARD_APP_ARGS(args, data);
00101
00102 if (!ast_strlen_zero(args.chan)) {
00103 char *prefix = alloca(strlen(args.chan) + 2);
00104 sprintf(prefix, "%s-", args.chan);
00105 if (!(chan = ast_get_channel_by_name_locked(args.chan)) && !(chan = ast_get_channel_by_name_prefix_locked(prefix, strlen(prefix)))) {
00106 ast_log(LOG_ERROR, "Channel '%s' not found! Variable '%s' will be blank.\n", args.chan, args.var);
00107 return -1;
00108 }
00109 } else
00110 ast_channel_lock(chan);
00111
00112 if (!(varstore = ast_channel_datastore_find(chan, &shared_variable_info, NULL))) {
00113 ast_channel_unlock(chan);
00114 return -1;
00115 }
00116
00117 varshead = varstore->data;
00118 *buf = '\0';
00119
00120
00121 AST_LIST_TRAVERSE(varshead, var, entries) {
00122 if (!strcmp(args.var, ast_var_name(var))) {
00123 ast_copy_string(buf, ast_var_value(var), len);
00124 break;
00125 }
00126 }
00127
00128 ast_channel_unlock(chan);
00129
00130 return 0;
00131 }
00132
00133 static int shared_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
00134 {
00135 struct ast_datastore *varstore;
00136 struct varshead *varshead;
00137 struct ast_var_t *var;
00138 AST_DECLARE_APP_ARGS(args,
00139 AST_APP_ARG(var);
00140 AST_APP_ARG(chan);
00141 );
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 (!(chan = ast_get_channel_by_name_locked(args.chan)) && !(chan = ast_get_channel_by_name_prefix_locked(prefix, strlen(prefix)))) {
00154 ast_log(LOG_ERROR, "Channel '%s' not found! Variable '%s' not set to '%s'.\n", args.chan, args.var, value);
00155 return -1;
00156 }
00157 } else
00158 ast_channel_lock(chan);
00159
00160 if (!(varstore = ast_channel_datastore_find(chan, &shared_variable_info, NULL))) {
00161 if (!(varstore = ast_channel_datastore_alloc(&shared_variable_info, NULL))) {
00162 ast_log(LOG_ERROR, "Unable to allocate new datastore. Shared variable not set.\n");
00163 ast_channel_unlock(chan);
00164 return -1;
00165 }
00166
00167 if (!(varshead = ast_calloc(1, sizeof(*varshead)))) {
00168 ast_log(LOG_ERROR, "Unable to allocate variable structure. Shared variable not set.\n");
00169 ast_channel_datastore_free(varstore);
00170 ast_channel_unlock(chan);
00171 return -1;
00172 }
00173
00174 varstore->data = varshead;
00175 ast_channel_datastore_add(chan, varstore);
00176 }
00177 varshead = varstore->data;
00178
00179
00180 AST_LIST_TRAVERSE(varshead, var, entries) {
00181
00182 if (!strcmp(args.var, ast_var_name(var))) {
00183 AST_LIST_REMOVE(varshead, var, entries);
00184 ast_var_delete(var);
00185 break;
00186 }
00187 }
00188
00189 var = ast_var_assign(args.var, S_OR(value, ""));
00190 AST_LIST_INSERT_HEAD(varshead, var, entries);
00191 manager_event(EVENT_FLAG_DIALPLAN, "VarSet",
00192 "Channel: %s\r\n"
00193 "Variable: SHARED(%s)\r\n"
00194 "Value: %s\r\n"
00195 "Uniqueid: %s\r\n",
00196 chan ? chan->name : "none", args.var, value,
00197 chan ? chan->uniqueid : "none");
00198
00199 ast_channel_unlock(chan);
00200
00201 return 0;
00202 }
00203
00204 static struct ast_custom_function shared_function = {
00205 .name = "SHARED",
00206 .synopsis = "Gets or sets the shared variable specified",
00207 .syntax = "SHARED(<varname>[,<channel>])",
00208 .desc =
00209 "Implements a shared variable area, in which you may share variables between\n"
00210 "channels. If channel is unspecified, defaults to the current channel. Note\n"
00211 "that the channel name may be the complete name (i.e. SIP/12-abcd1234) or the\n"
00212 "prefix only (i.e. SIP/12).\n"
00213 "\n"
00214 "The variables used in this space are separate from the general namespace of\n"
00215 "the channel and thus ${SHARED(foo)} and ${foo} represent two completely\n"
00216 "different variables, despite sharing the same name.\n"
00217 "\n"
00218 "Finally, realize that there is an inherent race between channels operating\n"
00219 "at the same time, fiddling with each others' internal variables, which is why\n"
00220 "this special variable namespace exists; it is to remind you that variables in\n"
00221 "the SHARED namespace may change at any time, without warning. You should\n"
00222 "therefore take special care to ensure that when using the SHARED namespace,\n"
00223 "you retrieve the variable and store it in a regular channel variable before\n"
00224 "using it in a set of calculations (or you might be surprised by the result).\n",
00225 .read = shared_read,
00226 .write = shared_write,
00227 };
00228
00229 static int unload_module(void)
00230 {
00231 int res = 0;
00232
00233 res |= ast_custom_function_unregister(&global_function);
00234 res |= ast_custom_function_unregister(&shared_function);
00235
00236 return res;
00237 }
00238
00239 static int load_module(void)
00240 {
00241 int res = 0;
00242
00243 res |= ast_custom_function_register(&global_function);
00244 res |= ast_custom_function_register(&shared_function);
00245
00246 return res;
00247 }
00248
00249 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Variable dialplan functions");