Fix documentation replication issues
[asterisk/asterisk.git] / funcs / func_global.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2006, Tilghman Lesher
5  *
6  * Tilghman Lesher <func_global__200605@the-tilghman.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief Global variable dialplan functions
22  *
23  * \author Tilghman Lesher <func_global__200605@the-tilghman.com>
24  *
25  * \ingroup functions
26  */
27
28 /*** MODULEINFO
29         <support_level>core</support_level>
30  ***/
31
32 #include "asterisk.h"
33
34 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
35
36 #include <sys/stat.h>
37
38 #include "asterisk/module.h"
39 #include "asterisk/pbx.h"
40 #include "asterisk/channel.h"
41 #include "asterisk/app.h"
42 #include "asterisk/stasis_channels.h"
43
44 /*** DOCUMENTATION
45         <function name="GLOBAL" language="en_US">
46                 <synopsis>
47                         Gets or sets the global variable specified.
48                 </synopsis>
49                 <syntax>
50                         <parameter name="varname" required="true">
51                                 <para>Global variable name</para>
52                         </parameter>
53                 </syntax>
54                 <description>
55                         <para>Set or get the value of a global variable specified in <replaceable>varname</replaceable></para>
56                 </description>
57         </function>
58         <function name="SHARED" language="en_US">
59                 <synopsis>
60                         Gets or sets the shared variable specified.
61                 </synopsis>
62                 <syntax>
63                         <parameter name="varname" required="true">
64                                 <para>Variable name</para>
65                         </parameter>
66                         <parameter name="channel">
67                                 <para>If not specified will default to current channel. It is the complete
68                                 channel name: <literal>SIP/12-abcd1234</literal> or the prefix only <literal>SIP/12</literal>.</para>
69                         </parameter>
70                 </syntax>
71                 <description>
72                         <para>Implements a shared variable area, in which you may share variables between
73                         channels.</para>
74                         <para>The variables used in this space are separate from the general namespace of
75                         the channel and thus <variable>SHARED(foo)</variable> and <variable>foo</variable> 
76                         represent two completely different variables, despite sharing the same name.</para>
77                         <para>Finally, realize that there is an inherent race between channels operating
78                         at the same time, fiddling with each others' internal variables, which is why
79                         this special variable namespace exists; it is to remind you that variables in
80                         the SHARED namespace may change at any time, without warning.  You should
81                         therefore take special care to ensure that when using the SHARED namespace,
82                         you retrieve the variable and store it in a regular channel variable before
83                         using it in a set of calculations (or you might be surprised by the result).</para>
84                 </description>
85         </function>
86         <managerEvent language="en_US" name="VarSet">
87                 <managerEventInstance class="EVENT_FLAG_DIALPLAN">
88                         <synopsis>Raised when a variable is shared between channels.</synopsis>
89                         <syntax>
90                                 <channel_snapshot/>
91                                 <parameter name="Variable">
92                                         <para>The SHARED variable being set.</para>
93                                         <note><para>The variable name will always be enclosed with
94                                         <literal>SHARED()</literal></para></note>
95                                 </parameter>
96                                 <parameter name="Value">
97                                         <para>The new value of the variable.</para>
98                                 </parameter>
99                         </syntax>
100                         <see-also>
101                                 <ref type="function">SHARED</ref>
102                         </see-also>
103                 </managerEventInstance>
104         </managerEvent>
105  ***/
106
107 static void shared_variable_free(void *data);
108
109 static const struct ast_datastore_info shared_variable_info = {
110         .type = "SHARED_VARIABLES",
111         .destroy = shared_variable_free,
112 };
113
114 static void shared_variable_free(void *data)
115 {
116         struct varshead *varshead = data;
117         struct ast_var_t *var;
118
119         while ((var = AST_LIST_REMOVE_HEAD(varshead, entries))) {
120                 ast_var_delete(var);
121         }
122         ast_free(varshead);
123 }
124
125 static int global_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
126 {
127         const char *var = pbx_builtin_getvar_helper(NULL, data);
128
129         *buf = '\0';
130
131         if (var)
132                 ast_copy_string(buf, var, len);
133
134         return 0;
135 }
136
137 static int global_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
138 {
139         pbx_builtin_setvar_helper(NULL, data, value);
140
141         return 0;
142 }
143
144 static struct ast_custom_function global_function = {
145         .name = "GLOBAL",
146         .read = global_read,
147         .write = global_write,
148 };
149
150 static int shared_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
151 {
152         struct ast_datastore *varstore;
153         struct varshead *varshead;
154         struct ast_var_t *var;
155         AST_DECLARE_APP_ARGS(args,
156                 AST_APP_ARG(var);
157                 AST_APP_ARG(chan);
158         );
159         struct ast_channel *c_ref = NULL;
160
161         if (ast_strlen_zero(data)) {
162                 ast_log(LOG_WARNING, "SHARED() requires an argument: SHARED(<var>[,<chan>])\n");
163                 return -1;
164         }
165
166         AST_STANDARD_APP_ARGS(args, data);
167
168         if (!ast_strlen_zero(args.chan)) {
169                 char *prefix = ast_alloca(strlen(args.chan) + 2);
170                 sprintf(prefix, "%s-", args.chan);
171                 if (!(c_ref = ast_channel_get_by_name(args.chan)) && !(c_ref = ast_channel_get_by_name_prefix(prefix, strlen(prefix)))) {
172                         ast_log(LOG_ERROR, "Channel '%s' not found!  Variable '%s' will be blank.\n", args.chan, args.var);
173                         return -1;
174                 }
175                 chan = c_ref;
176         }
177
178         ast_channel_lock(chan);
179
180         if (!(varstore = ast_channel_datastore_find(chan, &shared_variable_info, NULL))) {
181                 ast_channel_unlock(chan);
182                 if (c_ref) {
183                         c_ref = ast_channel_unref(c_ref);
184                 }
185                 return -1;
186         }
187
188         varshead = varstore->data;
189         *buf = '\0';
190
191         /* Protected by the channel lock */
192         AST_LIST_TRAVERSE(varshead, var, entries) {
193                 if (!strcmp(args.var, ast_var_name(var))) {
194                         ast_copy_string(buf, ast_var_value(var), len);
195                         break;
196                 }
197         }
198
199         ast_channel_unlock(chan);
200
201         if (c_ref) {
202                 c_ref = ast_channel_unref(c_ref);
203         }
204
205         return 0;
206 }
207
208 static int shared_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
209 {
210         struct ast_datastore *varstore;
211         struct varshead *varshead;
212         struct ast_var_t *var;
213         AST_DECLARE_APP_ARGS(args,
214                 AST_APP_ARG(var);
215                 AST_APP_ARG(chan);
216         );
217         struct ast_channel *c_ref = NULL;
218         int len;
219         RAII_VAR(char *, shared_buffer, NULL, ast_free);
220
221         if (ast_strlen_zero(data)) {
222                 ast_log(LOG_WARNING, "SHARED() requires an argument: SHARED(<var>[,<chan>])\n");
223                 return -1;
224         }
225
226         AST_STANDARD_APP_ARGS(args, data);
227
228         if (!ast_strlen_zero(args.chan)) {
229                 char *prefix = ast_alloca(strlen(args.chan) + 2);
230                 sprintf(prefix, "%s-", args.chan);
231                 if (!(c_ref = ast_channel_get_by_name(args.chan)) && !(c_ref = ast_channel_get_by_name_prefix(prefix, strlen(prefix)))) {
232                         ast_log(LOG_ERROR, "Channel '%s' not found!  Variable '%s' not set to '%s'.\n", args.chan, args.var, value);
233                         return -1;
234                 }
235                 chan = c_ref;
236         }
237
238         len = 9 + strlen(args.var); /* SHARED() + var */
239         shared_buffer = ast_malloc(len);
240         if (!shared_buffer) {
241                 if (c_ref) {
242                         ast_channel_unref(c_ref);
243                 }
244                 return -1;
245         }
246
247         ast_channel_lock(chan);
248
249         if (!(varstore = ast_channel_datastore_find(chan, &shared_variable_info, NULL))) {
250                 if (!(varstore = ast_datastore_alloc(&shared_variable_info, NULL))) {
251                         ast_log(LOG_ERROR, "Unable to allocate new datastore.  Shared variable not set.\n");
252                         ast_channel_unlock(chan);
253                         if (c_ref) {
254                                 c_ref = ast_channel_unref(c_ref);
255                         }
256                         return -1;
257                 }
258
259                 if (!(varshead = ast_calloc(1, sizeof(*varshead)))) {
260                         ast_log(LOG_ERROR, "Unable to allocate variable structure.  Shared variable not set.\n");
261                         ast_datastore_free(varstore);
262                         ast_channel_unlock(chan);
263                         if (c_ref) {
264                                 c_ref = ast_channel_unref(c_ref);
265                         }
266                         return -1;
267                 }
268
269                 varstore->data = varshead;
270                 ast_channel_datastore_add(chan, varstore);
271         }
272         varshead = varstore->data;
273
274         /* Protected by the channel lock */
275         AST_LIST_TRAVERSE_SAFE_BEGIN(varshead, var, entries) {
276                 /* If there's a previous value, remove it */
277                 if (!strcmp(args.var, ast_var_name(var))) {
278                         AST_LIST_REMOVE_CURRENT(entries);
279                         ast_var_delete(var);
280                         break;
281                 }
282         }
283         AST_LIST_TRAVERSE_SAFE_END;
284
285         var = ast_var_assign(args.var, S_OR(value, ""));
286         AST_LIST_INSERT_HEAD(varshead, var, entries);
287
288         sprintf(shared_buffer, "SHARED(%s)", args.var);
289         ast_channel_publish_varset(chan, shared_buffer, value);
290
291         ast_channel_unlock(chan);
292
293         if (c_ref) {
294                 c_ref = ast_channel_unref(c_ref);
295         }
296
297         return 0;
298 }
299
300 static struct ast_custom_function shared_function = {
301         .name = "SHARED",
302         .read = shared_read,
303         .write = shared_write,
304 };
305
306 static int unload_module(void)
307 {
308         int res = 0;
309
310         res |= ast_custom_function_unregister(&global_function);
311         res |= ast_custom_function_unregister(&shared_function);
312
313         return res;
314 }
315
316 static int load_module(void)
317 {
318         int res = 0;
319
320         res |= ast_custom_function_register(&global_function);
321         res |= ast_custom_function_register(&shared_function);
322
323         return res;
324 }
325
326 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Variable dialplan functions");