Automatically create new buddy upon reception of a presence stanza of
[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 #include "asterisk.h"
29
30 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
31
32 #include <sys/stat.h>
33
34 #include "asterisk/module.h"
35 #include "asterisk/pbx.h"
36 #include "asterisk/channel.h"
37 #include "asterisk/app.h"
38 #include "asterisk/manager.h"
39
40 static void shared_variable_free(void *data);
41
42 static struct ast_datastore_info shared_variable_info = {
43         .type = "SHARED_VARIABLES",
44         .destroy = shared_variable_free,
45 };
46
47 static void shared_variable_free(void *data)
48 {
49         struct varshead *varshead = data;
50         struct ast_var_t *var;
51
52         while ((var = AST_LIST_REMOVE_HEAD(varshead, entries))) {
53                 ast_var_delete(var);
54         }
55         ast_free(varshead);
56 }
57
58 static int global_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
59 {
60         const char *var = pbx_builtin_getvar_helper(NULL, data);
61
62         *buf = '\0';
63
64         if (var)
65                 ast_copy_string(buf, var, len);
66
67         return 0;
68 }
69
70 static int global_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
71 {
72         pbx_builtin_setvar_helper(NULL, data, value);
73
74         return 0;
75 }
76
77 static struct ast_custom_function global_function = {
78         .name = "GLOBAL",
79         .synopsis = "Gets or sets the global variable specified",
80         .syntax = "GLOBAL(<varname>)",
81         .read = global_read,
82         .write = global_write,
83 };
84
85 static int shared_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
86 {
87         struct ast_datastore *varstore;
88         struct varshead *varshead;
89         struct ast_var_t *var;
90         AST_DECLARE_APP_ARGS(args,
91                 AST_APP_ARG(var);
92                 AST_APP_ARG(chan);
93         );
94
95         if (ast_strlen_zero(data)) {
96                 ast_log(LOG_WARNING, "SHARED() requires an argument: SHARED(<var>[,<chan>])\n");
97                 return -1;
98         }
99
100         AST_STANDARD_APP_ARGS(args, data);
101
102         if (!ast_strlen_zero(args.chan)) {
103                 char *prefix = alloca(strlen(args.chan) + 2);
104                 sprintf(prefix, "%s-", args.chan);
105                 if (!(chan = ast_get_channel_by_name_locked(args.chan)) && !(chan = ast_get_channel_by_name_prefix_locked(prefix, strlen(prefix)))) {
106                         ast_log(LOG_ERROR, "Channel '%s' not found!  Variable '%s' will be blank.\n", args.chan, args.var);
107                         return -1;
108                 }
109         } else
110                 ast_channel_lock(chan);
111
112         if (!(varstore = ast_channel_datastore_find(chan, &shared_variable_info, NULL)))
113                 return -1;
114         varshead = varstore->data;
115         *buf = '\0';
116
117         /* Protected by the channel lock */
118         AST_LIST_TRAVERSE(varshead, var, entries) {
119                 if (!strcmp(args.var, ast_var_name(var))) {
120                         ast_copy_string(buf, ast_var_value(var), len);
121                         break;
122                 }
123         }
124
125         return 0;
126 }
127
128 static int shared_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
129 {
130         struct ast_datastore *varstore;
131         struct varshead *varshead;
132         struct ast_var_t *var;
133         AST_DECLARE_APP_ARGS(args,
134                 AST_APP_ARG(var);
135                 AST_APP_ARG(chan);
136         );
137
138         if (ast_strlen_zero(data)) {
139                 ast_log(LOG_WARNING, "SHARED() requires an argument: SHARED(<var>[,<chan>])\n");
140                 return -1;
141         }
142
143         AST_STANDARD_APP_ARGS(args, data);
144
145         if (!ast_strlen_zero(args.chan)) {
146                 char *prefix = alloca(strlen(args.chan) + 2);
147                 sprintf(prefix, "%s-", args.chan);
148                 if (!(chan = ast_get_channel_by_name_locked(args.chan)) && !(chan = ast_get_channel_by_name_prefix_locked(prefix, strlen(prefix)))) {
149                         ast_log(LOG_ERROR, "Channel '%s' not found!  Variable '%s' not set to '%s'.\n", args.chan, args.var, value);
150                         return -1;
151                 }
152         } else
153                 ast_channel_lock(chan);
154
155         if (!(varstore = ast_channel_datastore_find(chan, &shared_variable_info, NULL))) {
156                 if (!(varstore = ast_channel_datastore_alloc(&shared_variable_info, NULL))) {
157                         ast_log(LOG_ERROR, "Unable to allocate new datastore.  Shared variable not set.\n");
158                         ast_channel_unlock(chan);
159                         return -1;
160                 }
161
162                 if (!(varshead = ast_calloc(1, sizeof(*varshead)))) {
163                         ast_log(LOG_ERROR, "Unable to allocate variable structure.  Shared variable not set.\n");
164                         ast_channel_datastore_free(varstore);
165                         ast_channel_unlock(chan);
166                         return -1;
167                 }
168
169                 varstore->data = varshead;
170                 ast_channel_datastore_add(chan, varstore);
171         }
172         varshead = varstore->data;
173
174         /* Protected by the channel lock */
175         AST_LIST_TRAVERSE(varshead, var, entries) {
176                 /* If there's a previous value, remove it */
177                 if (!strcmp(args.var, ast_var_name(var))) {
178                         AST_LIST_REMOVE(varshead, var, entries);
179                         ast_var_delete(var);
180                         break;
181                 }
182         }
183
184         var = ast_var_assign(args.var, S_OR(value, ""));
185         AST_LIST_INSERT_HEAD(varshead, var, entries);
186         manager_event(EVENT_FLAG_DIALPLAN, "VarSet", 
187                 "Channel: %s\r\n"
188                 "Variable: SHARED(%s)\r\n"
189                 "Value: %s\r\n"
190                 "Uniqueid: %s\r\n", 
191                 chan ? chan->name : "none", args.var, value, 
192                 chan ? chan->uniqueid : "none");
193
194         ast_channel_unlock(chan);
195
196         return 0;
197 }
198
199 static struct ast_custom_function shared_function = {
200         .name = "SHARED",
201         .synopsis = "Gets or sets the shared variable specified",
202         .syntax = "SHARED(<varname>[,<channel>])",
203         .desc =
204 "Implements a shared variable area, in which you may share variables between\n"
205 "channels.  If channel is unspecified, defaults to the current channel.  Note\n"
206 "that the channel name may be the complete name (i.e. SIP/12-abcd1234) or the\n"
207 "prefix only (i.e. SIP/12).\n"
208 "\n"
209 "The variables used in this space are separate from the general namespace of\n"
210 "the channel and thus ${SHARED(foo)} and ${foo} represent two completely\n"
211 "different variables, despite sharing the same name.\n"
212 "\n"
213 "Finally, realize that there is an inherent race between channels operating\n"
214 "at the same time, fiddling with each others' internal variables, which is why\n"
215 "this special variable namespace exists; it is to remind you that variables in\n"
216 "the SHARED namespace may change at any time, without warning.  You should\n"
217 "therefore take special care to ensure that when using the SHARED namespace,\n"
218 "you retrieve the variable and store it in a regular channel variable before\n"
219 "using it in a set of calculations (or you might be surprised by the result).\n",
220         .read = shared_read,
221         .write = shared_write,
222 };
223
224 static int unload_module(void)
225 {
226         int res = 0;
227
228         res |= ast_custom_function_unregister(&global_function);
229         res |= ast_custom_function_unregister(&shared_function);
230
231         return res;
232 }
233
234 static int load_module(void)
235 {
236         int res = 0;
237
238         res |= ast_custom_function_register(&global_function);
239         res |= ast_custom_function_register(&shared_function);
240
241         return res;
242 }
243
244 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Variable dialplan functions");