Add REALTIME_STORE and REALTIME_DESTROY dialplan functions provided by sergee.
[asterisk/asterisk.git] / funcs / func_realtime.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2005-2006, BJ Weschke. All rights reserved.
5  * 
6  * BJ Weschke <bweschke@btwtech.com>
7  * 
8  * This code is released by the author with no restrictions on usage. 
9  *
10  * See http://www.asterisk.org for more information about
11  * the Asterisk project. Please do not directly contact
12  * any of the maintainers of this project for assistance;
13  * the project provides a web site, mailing lists and IRC
14  * channels for your use.
15  *
16  */
17
18 /*! \file
19  *
20  * \brief REALTIME dialplan function
21  * 
22  * \author BJ Weschke <bweschke@btwtech.com>
23  * 
24  * \ingroup functions
25  */
26
27 #include "asterisk.h"
28
29 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
30
31 #include "asterisk/file.h"
32 #include "asterisk/channel.h"
33 #include "asterisk/pbx.h"
34 #include "asterisk/config.h"
35 #include "asterisk/module.h"
36 #include "asterisk/lock.h"
37 #include "asterisk/utils.h"
38 #include "asterisk/app.h"
39
40 static int function_realtime_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) 
41 {
42         struct ast_variable *var, *head;
43         struct ast_str *out;
44         size_t resultslen;
45         int n;
46         AST_DECLARE_APP_ARGS(args,
47                 AST_APP_ARG(family);
48                 AST_APP_ARG(fieldmatch);
49                 AST_APP_ARG(value);
50                 AST_APP_ARG(delim1);
51                 AST_APP_ARG(delim2);
52         );
53
54         if (ast_strlen_zero(data)) {
55                 ast_log(LOG_WARNING, "Syntax: REALTIME(family,fieldmatch[,value[,delim1[,delim2]]]) - missing argument!\n");
56                 return -1;
57         }
58
59         AST_STANDARD_APP_ARGS(args, data);
60
61         if (!args.delim1)
62                 args.delim1 = ",";
63         if (!args.delim2)
64                 args.delim2 = "=";
65
66         if (chan)
67                 ast_autoservice_start(chan);
68
69         head = ast_load_realtime_all(args.family, args.fieldmatch, args.value, NULL);
70
71         if (!head) {
72                 if (chan)
73                         ast_autoservice_stop(chan);
74                 return -1;
75         }
76
77         resultslen = 0;
78         n = 0;
79         for (var = head; var; n++, var = var->next)
80                 resultslen += strlen(var->name) + strlen(var->value);
81         /* add space for delimiters and final '\0' */
82         resultslen += n * (strlen(args.delim1) + strlen(args.delim2)) + 1;
83
84         out = ast_str_alloca(resultslen);
85         for (var = head; var; var = var->next)
86                 ast_str_append(&out, 0, "%s%s%s%s", var->name, args.delim2, var->value, args.delim1);
87         ast_copy_string(buf, out->str, len);
88
89         if (chan)
90                 ast_autoservice_stop(chan);
91
92         return 0;
93 }
94
95 static int function_realtime_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
96 {
97         int res = 0;
98         AST_DECLARE_APP_ARGS(args,
99                 AST_APP_ARG(family);
100                 AST_APP_ARG(fieldmatch);
101                 AST_APP_ARG(value);
102                 AST_APP_ARG(field);
103         );
104
105         if (ast_strlen_zero(data)) {
106                 ast_log(LOG_WARNING, "Syntax: REALTIME(family,fieldmatch,value,newcol) - missing argument!\n");
107                 return -1;
108         }
109
110         if (chan)
111                 ast_autoservice_start(chan);
112
113         AST_STANDARD_APP_ARGS(args, data);
114
115         res = ast_update_realtime(args.family, args.fieldmatch, args.value, args.field, (char *)value, NULL);
116
117         if (res < 0) {
118                 ast_log(LOG_WARNING, "Failed to update. Check the debug log for possible data repository related entries.\n");
119         }
120
121         if (chan)
122                 ast_autoservice_stop(chan);
123
124         return 0;
125 }
126
127 static int function_realtime_store(struct ast_channel *chan, const char *cmd, char *data, const char *value)
128 {
129         int res = 0;
130         char storeid[32];
131         char *valcopy;
132         AST_DECLARE_APP_ARGS(a,
133                 AST_APP_ARG(family);
134                 AST_APP_ARG(f)[30]; /* fields */
135         );
136
137         AST_DECLARE_APP_ARGS(v,
138                 AST_APP_ARG(v)[30]; /* values */
139         );
140
141         if (ast_strlen_zero(data)) {
142                 ast_log(LOG_WARNING, "Syntax: REALTIME_STORE(family,field1,field2,...,field30) - missing argument!\n");
143                 return -1;
144         }
145
146         if (chan)
147                 ast_autoservice_start(chan);
148
149         valcopy = ast_strdupa(value);
150         AST_STANDARD_APP_ARGS(a, data);
151         AST_STANDARD_APP_ARGS(v, valcopy);
152
153         res = ast_store_realtime(a.family, 
154                 a.f[0], v.v[0], a.f[1], v.v[1], a.f[2], v.v[2], a.f[3], v.v[3], a.f[4], v.v[4],
155                 a.f[5], v.v[5], a.f[6], v.v[6], a.f[7], v.v[7], a.f[8], v.v[8], a.f[9], v.v[9],
156                 a.f[10], v.v[10], a.f[11], v.v[11], a.f[12], v.v[12], a.f[13], v.v[13], a.f[14], v.v[14],
157                 a.f[15], v.v[15], a.f[16], v.v[16], a.f[17], v.v[17], a.f[18], v.v[18], a.f[19], v.v[19],
158                 a.f[20], v.v[20], a.f[21], v.v[21], a.f[22], v.v[22], a.f[23], v.v[23], a.f[24], v.v[24],
159                 a.f[25], v.v[25], a.f[26], v.v[26], a.f[27], v.v[27], a.f[28], v.v[28], a.f[29], v.v[29], NULL
160         );
161
162         if (res < 0) {
163                 ast_log(LOG_WARNING, "Failed to store. Check the debug log for possible data repository related entries.\n");
164         } else {
165                 snprintf(storeid, sizeof(storeid), "%d", res);
166                 pbx_builtin_setvar_helper(chan, "RTSTOREID", storeid);
167         }
168
169         if (chan)
170                 ast_autoservice_stop(chan);
171
172         return 0;
173 }
174
175 static int function_realtime_readdestroy(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) 
176 {
177         struct ast_variable *var, *head;
178         struct ast_str *out;
179         size_t resultslen;
180         int n;
181         AST_DECLARE_APP_ARGS(args,
182                 AST_APP_ARG(family);
183                 AST_APP_ARG(fieldmatch);
184                 AST_APP_ARG(value);
185                 AST_APP_ARG(delim1);
186                 AST_APP_ARG(delim2);
187         );
188
189         if (ast_strlen_zero(data)) {
190                 ast_log(LOG_WARNING, "Syntax: REALTIME_DESTROY(family,fieldmatch[,value[,delim1[,delim2]]]) - missing argument!\n");
191                 return -1;
192         }
193
194         AST_STANDARD_APP_ARGS(args, data);
195
196         if (!args.delim1)
197                 args.delim1 = ",";
198         if (!args.delim2)
199                 args.delim2 = "=";
200
201         if (chan)
202                 ast_autoservice_start(chan);
203
204         head = ast_load_realtime_all(args.family, args.fieldmatch, args.value, NULL);
205
206         if (!head) {
207                 if (chan)
208                         ast_autoservice_stop(chan);
209                 return -1;
210         }
211
212         resultslen = 0;
213         n = 0;
214         for (var = head; var; n++, var = var->next)
215                 resultslen += strlen(var->name) + strlen(var->value);
216         /* add space for delimiters and final '\0' */
217         resultslen += n * (strlen(args.delim1) + strlen(args.delim2)) + 1;
218
219         out = ast_str_alloca(resultslen);
220         for (var = head; var; var = var->next) {
221                 ast_str_append(&out, 0, "%s%s%s%s", var->name, args.delim2, var->value, args.delim1);
222         }
223         ast_copy_string(buf, out->str, len);
224
225         ast_destroy_realtime(args.family, args.fieldmatch, args.value, NULL);
226
227         if (chan)
228                 ast_autoservice_stop(chan);
229
230         return 0;
231 }
232
233 struct ast_custom_function realtime_function = {
234         .name = "REALTIME",
235         .synopsis = "RealTime Read/Write Functions",
236         .syntax = "REALTIME(family,fieldmatch[,value[,delim1[,delim2]]]) on read\n"
237                   "REALTIME(family,fieldmatch,value,field) on write",
238         .desc = "This function will read or write values from/to a RealTime repository.\n"
239                 "REALTIME(....) will read names/values from the repository, and \n"
240                 "REALTIME(....)= will write a new value/field to the repository. On a\n"
241                 "read, this function returns a delimited text string. The name/value \n"
242                 "pairs are delimited by delim1, and the name and value are delimited \n"
243                 "between each other with delim2. The default for delim1 is ',' and   \n"
244                 "the default for delim2 is '='. If there is no match, NULL will be   \n"
245                 "returned by the function. On a write, this function will always     \n"
246                 "return NULL. \n",
247         .read = function_realtime_read,
248         .write = function_realtime_write,
249 };
250
251 struct ast_custom_function realtime_store_function = {
252         .name = "REALTIME_STORE",
253         .synopsis = "RealTime Store Function",
254         .syntax = "REALTIME_STORE(family,field1,field2,...,field30) = value1,value2,...,value30",
255         .desc = "This function will insert a new set of values into the RealTime repository.\n"
256                 "If RT engine provides an unique ID of the stored record, REALTIME_STORE(...)=..\n"
257                 "creates channel variable named RTSTOREID, which contains value of unique ID.\n"
258                 "Currently, a maximum of 30 field/value pairs is supported.\n",
259         .write = function_realtime_store,
260 };
261
262 struct ast_custom_function realtime_destroy_function = {
263         .name = "REALTIME_DESTROY",
264         .synopsis = "RealTime Destroy Function",
265         .syntax = "REALTIME_DESTROY(family,fieldmatch[,value[,delim1[,delim2]]])\n",
266         .desc = "This function acts in the same way as REALTIME(....) does, except that\n"
267                 "it destroys matched record in RT engine.\n",
268         .read = function_realtime_readdestroy,
269 };
270
271 static int unload_module(void)
272 {
273         int res = 0;
274         res |= ast_custom_function_unregister(&realtime_function);
275         res |= ast_custom_function_unregister(&realtime_store_function);
276         res |= ast_custom_function_unregister(&realtime_destroy_function);
277         return res;
278 }
279
280 static int load_module(void)
281 {
282         int res = 0;
283         res |= ast_custom_function_register(&realtime_function);
284         res |= ast_custom_function_register(&realtime_store_function);
285         res |= ast_custom_function_register(&realtime_destroy_function);
286         return res;
287 }
288
289 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Read/Write/Store/Destroy values from a RealTime repository");